Source/WebCore: ctrl-arrows, ctrl-shift-arrow, ctrl-backspace
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Jan 2013 11:53:04 +0000 (11:53 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Jan 2013 11:53:04 +0000 (11:53 +0000)
Web Inspector: implmenet Ctrl-Arrow/Ctrl-Backspace in DefaultTextEditor
https://bugs.webkit.org/show_bug.cgi?id=107944

Patch by Andrey Lushnikov <lushnikov@chromium.org> on 2013-01-30
Reviewed by Pavel Feldman.

Add ctrl-arrows/ctrl-shift-arrow/ctrl-backspace shortcuts to jump over
and delete words.

New test: inspector/editor/text-editor-ctrl-movements.html

* inspector/front-end/DefaultTextEditor.js:
(WebInspector.DefaultTextEditor):
(WebInspector.DefaultTextEditor.prototype._registerShortcuts):
(WebInspector.DefaultTextEditor.prototype.selection):
(WebInspector.DefaultTextEditor.WordMovementController): Added.
(WebInspector.DefaultTextEditor.WordMovementController.prototype._registerShortcuts):
(WebInspector.DefaultTextEditor.WordMovementController.prototype.):
(WebInspector.DefaultTextEditor.WordMovementController.prototype._rangeForCtrlArrowMove):
(WebInspector.DefaultTextEditor.WordMovementController.prototype._handleCtrlArrow):
(WebInspector.DefaultTextEditor.WordMovementController.prototype._handleCtrlShiftArrow):
(WebInspector.DefaultTextEditor.WordMovementController.prototype._handleCtrlBackspace):

LayoutTests: Web Inspector: implmenet Ctrl-Arrow/Ctrl-Backspace in DefaultTextEditor
https://bugs.webkit.org/show_bug.cgi?id=107944

Patch by Andrey Lushnikov <lushnikov@chromium.org> on 2013-01-30
Reviewed by Pavel Feldman.

Add new test to verify ctrl-arrow/ctrl-backspace behavior. Exclude
this test on the platforms that do not currently support eventSender.

* inspector/editor/text-editor-ctrl-movements-expected.txt: Added.
* inspector/editor/text-editor-ctrl-movements.html: Added.
* platform/efl/TestExpectations:
* platform/mac/TestExpectations:
* platform/qt/TestExpectations:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@141245 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/inspector/editor/text-editor-ctrl-movements-expected.txt [new file with mode: 0644]
LayoutTests/inspector/editor/text-editor-ctrl-movements.html [new file with mode: 0644]
LayoutTests/platform/efl/TestExpectations
LayoutTests/platform/mac/TestExpectations
LayoutTests/platform/qt/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/inspector/front-end/DefaultTextEditor.js
Source/WebCore/inspector/front-end/TextEditor.js

index 16f477b..c2a80ee 100644 (file)
@@ -1,5 +1,21 @@
 2013-01-30  Andrey Lushnikov  <lushnikov@chromium.org>
 
+        Web Inspector: implmenet Ctrl-Arrow/Ctrl-Backspace in DefaultTextEditor
+        https://bugs.webkit.org/show_bug.cgi?id=107944
+
+        Reviewed by Pavel Feldman.
+
+        Add new test to verify ctrl-arrow/ctrl-backspace behavior. Exclude
+        this test on the platforms that do not currently support eventSender.
+
+        * inspector/editor/text-editor-ctrl-movements-expected.txt: Added.
+        * inspector/editor/text-editor-ctrl-movements.html: Added.
+        * platform/efl/TestExpectations:
+        * platform/mac/TestExpectations:
+        * platform/qt/TestExpectations:
+
+2013-01-30  Andrey Lushnikov  <lushnikov@chromium.org>
+
         Web Inspector: do not repaint all lines in highlight regex API in DTE
         https://bugs.webkit.org/show_bug.cgi?id=108081
 
diff --git a/LayoutTests/inspector/editor/text-editor-ctrl-movements-expected.txt b/LayoutTests/inspector/editor/text-editor-ctrl-movements-expected.txt
new file mode 100644 (file)
index 0000000..0e7f9cb
--- /dev/null
@@ -0,0 +1,503 @@
+This test checks how text editor handles different ctrl-based movements, i.e. ctrl-left, ctrl-right, ctrl-shift-left, ctrl-backspace.
+
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}
+
+Running: testCtrlRightArrow
+|function testFunction(foo, bar)
+function| testFunction(foo, bar)
+function testFunction|(foo, bar)
+function testFunction(|foo, bar)
+function testFunction(foo|, bar)
+function testFunction(foo,| bar)
+function testFunction(foo, bar|)
+function testFunction(foo, bar)|
+|{
+{|
+|    someFunctionCall(bar);
+    someFunctionCall|(bar);
+    someFunctionCall(|bar);
+    someFunctionCall(bar|);
+    someFunctionCall(bar);|
+|    var b = 42;
+    var| b = 42;
+    var b| = 42;
+    var b =| 42;
+    var b = 42|;
+    var b = 42;|
+|    return a === 1 ? true : false;
+    return| a === 1 ? true : false;
+    return a| === 1 ? true : false;
+    return a ===| 1 ? true : false;
+    return a === 1| ? true : false;
+    return a === 1 ?| true : false;
+    return a === 1 ? true| : false;
+    return a === 1 ? true :| false;
+    return a === 1 ? true : false|;
+    return a === 1 ? true : false;|
+|}
+}|
+}|
+
+Running: testCtrlLeftArrow
+}|
+|}
+    return a === 1 ? true : false;|
+    return a === 1 ? true : false|;
+    return a === 1 ? true : |false;
+    return a === 1 ? true |: false;
+    return a === 1 ? |true : false;
+    return a === 1 |? true : false;
+    return a === |1 ? true : false;
+    return a |=== 1 ? true : false;
+    return |a === 1 ? true : false;
+    |return a === 1 ? true : false;
+|    return a === 1 ? true : false;
+    var b = 42;|
+    var b = 42|;
+    var b = |42;
+    var b |= 42;
+    var |b = 42;
+    |var b = 42;
+|    var b = 42;
+    someFunctionCall(bar);|
+    someFunctionCall(bar|);
+    someFunctionCall(|bar);
+    someFunctionCall|(bar);
+    |someFunctionCall(bar);
+|    someFunctionCall(bar);
+{|
+|{
+function testFunction(foo, bar)|
+function testFunction(foo, bar|)
+function testFunction(foo, |bar)
+function testFunction(foo|, bar)
+function testFunction(|foo, bar)
+function testFunction|(foo, bar)
+function |testFunction(foo, bar)
+|function testFunction(foo, bar)
+|function testFunction(foo, bar)
+
+Running: testCtrlShiftRightArrow
+|function testFunction(foo, bar)
+>>function<<
+>>function testFunction<<
+>>function testFunction(<<
+>>function testFunction(foo<<
+>>function testFunction(foo,<<
+>>function testFunction(foo, bar<<
+>>function testFunction(foo, bar)<<
+>>function testFunction(foo, bar)
+<<
+>>function testFunction(foo, bar)
+{<<
+>>function testFunction(foo, bar)
+{
+<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b =<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a ===<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ?<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true :<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+
+Running: testCtrlShiftLeftArrow
+}|
+>>}<<
+>>
+}<<
+>>;
+}<<
+>>false;
+}<<
+>>: false;
+}<<
+>>true : false;
+}<<
+>>? true : false;
+}<<
+>>1 ? true : false;
+}<<
+>>=== 1 ? true : false;
+}<<
+>>a === 1 ? true : false;
+}<<
+>>return a === 1 ? true : false;
+}<<
+>>    return a === 1 ? true : false;
+}<<
+>>
+    return a === 1 ? true : false;
+}<<
+>>;
+    return a === 1 ? true : false;
+}<<
+>>42;
+    return a === 1 ? true : false;
+}<<
+>>= 42;
+    return a === 1 ? true : false;
+}<<
+>>b = 42;
+    return a === 1 ? true : false;
+}<<
+>>var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+>>function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}<<
+
+Running: testCtrlBackspace
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+<<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;<<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false<<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : <<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true <<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? <<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 <<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === <<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a <<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return <<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    <<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+<<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;<<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42<<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = <<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b <<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var <<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    <<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+<<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);<<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar<<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall(<<
+===============
+function testFunction(foo, bar)
+{
+    someFunctionCall<<
+===============
+function testFunction(foo, bar)
+{
+    <<
+===============
+function testFunction(foo, bar)
+{
+<<
+===============
+function testFunction(foo, bar)
+{<<
+===============
+function testFunction(foo, bar)
+<<
+===============
+function testFunction(foo, bar)<<
+===============
+function testFunction(foo, bar<<
+===============
+function testFunction(foo, <<
+===============
+function testFunction(foo<<
+===============
+function testFunction(<<
+===============
+function testFunction<<
+===============
+function <<
+===============
+<<
+
diff --git a/LayoutTests/inspector/editor/text-editor-ctrl-movements.html b/LayoutTests/inspector/editor/text-editor-ctrl-movements.html
new file mode 100644 (file)
index 0000000..cb242d8
--- /dev/null
@@ -0,0 +1,127 @@
+<html>
+<head>
+<script src="../../http/tests/inspector/inspector-test.js"></script>
+<script src="editor-test.js"></script>
+<script>
+function test()
+{
+function testFunction(foo, bar)
+{
+    someFunctionCall(bar);
+    var b = 42;
+    return a === 1 ? true : false;
+}
+
+    var textEditor = InspectorTest.createTestEditor();
+    textEditor.overrideViewportForTest(0, undefined, 3);
+    textEditor.mimeType = "text/javascript";
+    textEditor.setReadOnly(false);
+    textEditor.setText(testFunction.toString());
+    textEditor.element.focus();
+
+    InspectorTest.addResult(textEditor.text());
+
+    function dumpEditorSelection()
+    {
+        var selection = textEditor.selection();
+        if (selection.isEmpty()) {
+            var line = textEditor.line(selection.startLine);
+            InspectorTest.addResult(line.substring(0, selection.startColumn) + "|" + line.substring(selection.startColumn));
+        } else {
+            InspectorTest.addResult(">>" + textEditor._textModel.copyRange(selection.normalize()) + "<<");
+        }
+        return selection;
+    }
+
+    function setCursorAtBeginning()
+    {
+        textEditor.setSelection(WebInspector.TextRange.createFromLocation(0, 0));
+    }
+
+    function setCursorAtEnd()
+    {
+        var lastLine = textEditor._textModel.linesCount - 1;
+        var lastColumn = textEditor._textModel.line(lastLine).length;
+        textEditor.setSelection(WebInspector.TextRange.createFromLocation(lastLine, lastColumn));
+    }
+
+    InspectorTest.runTestSuite([
+        function testCtrlRightArrow(next)
+        {
+            setCursorAtBeginning();
+            var selection = dumpEditorSelection();
+            var oldSelection;
+            do {
+                oldSelection = selection;
+                eventSender.keyDown("rightArrow", ["ctrlKey"]);
+                selection = dumpEditorSelection();
+            } while (selection.compareTo(oldSelection) !== 0);
+            next();
+        },
+
+        function testCtrlLeftArrow(next)
+        {
+            setCursorAtEnd();
+            var selection = dumpEditorSelection();
+            var oldSelection;
+            do {
+                oldSelection = selection;
+                eventSender.keyDown("leftArrow", ["ctrlKey"]);
+                selection = dumpEditorSelection();
+            } while (selection.compareTo(oldSelection) !== 0);
+            next();
+        },
+
+        function testCtrlShiftRightArrow(next)
+        {
+            setCursorAtBeginning();
+            var selection = dumpEditorSelection();
+            var oldSelection;
+            do {
+                oldSelection = selection;
+                eventSender.keyDown("rightArrow", ["ctrlKey", "shiftKey"]);
+                selection = dumpEditorSelection();
+            } while (selection.collapseToEnd().compareTo(oldSelection.collapseToEnd()) !== 0);
+            next();
+        },
+
+        function testCtrlShiftLeftArrow(next)
+        {
+            setCursorAtEnd();
+            var selection = dumpEditorSelection();
+            var oldSelection;
+            do {
+                oldSelection = selection;
+                eventSender.keyDown("leftArrow", ["ctrlKey", "shiftKey"]);
+                selection = dumpEditorSelection();
+            } while (selection.collapseToEnd().compareTo(oldSelection.collapseToEnd()) !== 0);
+            next();
+        },
+
+        function testCtrlBackspace(next)
+        {
+            setCursorAtEnd();
+            InspectorTest.addResult("===============");
+            InspectorTest.addResult(textEditor.text());
+            do {
+                eventSender.keyDown("\b", ["ctrlKey"]);
+                InspectorTest.addResult("===============");
+                InspectorTest.addResult(textEditor.text() + "<<");
+            } while (textEditor.text() !== "");
+            textEditor.setText(testFunction.toString());
+            next();
+        }
+    ]);
+
+}
+
+</script>
+</head>
+
+<body onload="runTest();">
+<p>
+This test checks how text editor handles different ctrl-based movements, i.e. ctrl-left, ctrl-right, ctrl-shift-left, ctrl-backspace.
+</p>
+
+</body>
+</html>
index e3a188f..2b437cc 100644 (file)
@@ -1797,6 +1797,7 @@ webkit.org/b/106743 media/video-controls-captions.html [ Failure ]
 # New inspector/editor/text-editor-formatter.html introduced in r139617 fails on EFL, Mac, QT
 # https://bugs.webkit.org/show_bug.cgi?id=106883
 inspector/editor/text-editor-formatter.html
+inspector/editor/text-editor-ctrl-movements.html
 
 # Test fails on JSC platforms due to GC timing problems
 webkit.org/b/106957 svg/dom/SVGViewSpec-invalid-ref-crash.html [ Failure ]
index 9e33555..214d26d 100644 (file)
@@ -240,6 +240,7 @@ animations/play-state.html
 # window.eventSender doesn't exist in devtools front-end on mac.
 # https://bugs.webkit.org/show_bug.cgi?id=106793
 inspector/editor/text-editor-formatter.html [ Skip ]
+inspector/editor/text-editor-ctrl-movements.html [ Skip ]
 
 # https://bugs.webkit.org/show_bug.cgi?id=71120
 inspector/debugger/selected-call-frame-after-formatting-source.html
index fa7b12d..ad78ceb 100644 (file)
@@ -2555,6 +2555,7 @@ webkit.org/b/39725 fast/events/drag-and-drop-autoscroll.html [ Skip ]
 # New inspector/editor/text-editor-formatter.html introduced in r139617 fails on EFL, Mac, QT
 # https://bugs.webkit.org/show_bug.cgi?id=106883
 inspector/editor/text-editor-formatter.html
+inspector/editor/text-editor-ctrl-movements.html
 
 # Needs rebaseline after https://bugs.webkit.org/show_bug.cgi?id=14664
 webkit.org/b/107476 fast/block/float/024.html [ Failure ]
index 61b5bb5..0abe9f0 100644 (file)
@@ -1,5 +1,31 @@
 2013-01-30  Andrey Lushnikov  <lushnikov@chromium.org>
 
+        ctrl-arrows, ctrl-shift-arrow, ctrl-backspace
+
+        Web Inspector: implmenet Ctrl-Arrow/Ctrl-Backspace in DefaultTextEditor
+        https://bugs.webkit.org/show_bug.cgi?id=107944
+
+        Reviewed by Pavel Feldman.
+
+        Add ctrl-arrows/ctrl-shift-arrow/ctrl-backspace shortcuts to jump over
+        and delete words.
+
+        New test: inspector/editor/text-editor-ctrl-movements.html
+
+        * inspector/front-end/DefaultTextEditor.js:
+        (WebInspector.DefaultTextEditor):
+        (WebInspector.DefaultTextEditor.prototype._registerShortcuts):
+        (WebInspector.DefaultTextEditor.prototype.selection):
+        (WebInspector.DefaultTextEditor.WordMovementController): Added.
+        (WebInspector.DefaultTextEditor.WordMovementController.prototype._registerShortcuts):
+        (WebInspector.DefaultTextEditor.WordMovementController.prototype.):
+        (WebInspector.DefaultTextEditor.WordMovementController.prototype._rangeForCtrlArrowMove):
+        (WebInspector.DefaultTextEditor.WordMovementController.prototype._handleCtrlArrow):
+        (WebInspector.DefaultTextEditor.WordMovementController.prototype._handleCtrlShiftArrow):
+        (WebInspector.DefaultTextEditor.WordMovementController.prototype._handleCtrlBackspace):
+
+2013-01-30  Andrey Lushnikov  <lushnikov@chromium.org>
+
         Web Inspector: do not repaint all lines in highlight regex API in DTE
         https://bugs.webkit.org/show_bug.cgi?id=108081
 
index fe7d73d..048c365 100644 (file)
@@ -94,6 +94,7 @@ WebInspector.DefaultTextEditor = function(url, delegate)
     this.element.addEventListener("keydown", this._handleKeyDown.bind(this), false);
     this.element.addEventListener("contextmenu", this._contextMenu.bind(this), true);
 
+    this._wordMovementController = new WebInspector.DefaultTextEditor.WordMovementController(this, this._textModel);
     this._registerShortcuts();
 }
 
@@ -411,6 +412,8 @@ WebInspector.DefaultTextEditor.prototype = {
         var handleShiftTabKey = this._mainPanel.handleTabKeyPress.bind(this._mainPanel, true);
         this._shortcuts[WebInspector.KeyboardShortcut.makeKey(keys.Tab.code)] = handleTabKey;
         this._shortcuts[WebInspector.KeyboardShortcut.makeKey(keys.Tab.code, modifiers.Shift)] = handleShiftTabKey;
+
+        this._wordMovementController._registerShortcuts(this._shortcuts);
     },
 
     _handleSelectAll: function()
@@ -469,7 +472,7 @@ WebInspector.DefaultTextEditor.prototype = {
     /**
      * @return {WebInspector.TextRange}
      */
-    selection: function(textRange)
+    selection: function()
     {
         return this._mainPanel.selection();
     },
@@ -3118,4 +3121,137 @@ WebInspector.TextEditorMainPanel.TokenHighlighter.prototype = {
     }
 }
 
+/**
+ * @constructor
+ * @param {WebInspector.TextEditorModel} textModel
+ * @param {WebInspector.TextEditor} textEditor
+ */
+WebInspector.DefaultTextEditor.WordMovementController = function(textEditor, textModel)
+{
+    this._textModel = textModel;
+    this._textEditor = textEditor;
+}
+
+WebInspector.DefaultTextEditor.WordMovementController.prototype = {
+
+    /**
+     * @param {Object.<number, function()>} shortcuts
+     */
+    _registerShortcuts: function(shortcuts)
+    {
+        var keys = WebInspector.KeyboardShortcut.Keys;
+        var modifiers = WebInspector.KeyboardShortcut.Modifiers;
+
+        const wordJumpModifier = WebInspector.isMac() ? modifiers.Alt : modifiers.Ctrl;
+        shortcuts[WebInspector.KeyboardShortcut.makeKey(keys.Backspace.code, wordJumpModifier)] = this._handleCtrlBackspace.bind(this);
+        shortcuts[WebInspector.KeyboardShortcut.makeKey(keys.Left.code, wordJumpModifier)] = this._handleCtrlArrow.bind(this, "left");
+        shortcuts[WebInspector.KeyboardShortcut.makeKey(keys.Right.code, wordJumpModifier)] = this._handleCtrlArrow.bind(this, "right");
+        shortcuts[WebInspector.KeyboardShortcut.makeKey(keys.Left.code, modifiers.Shift | wordJumpModifier)] = this._handleCtrlShiftArrow.bind(this, "left");
+        shortcuts[WebInspector.KeyboardShortcut.makeKey(keys.Right.code, modifiers.Shift | wordJumpModifier)] = this._handleCtrlShiftArrow.bind(this, "right");
+    },
+
+    /**
+     * @param {WebInspector.TextRange} selection
+     * @param {string} direction
+     * @return {WebInspector.TextRange}
+     */
+    _rangeForCtrlArrowMove: function(selection, direction)
+    {
+        /**
+         * @param {string} char
+         */
+        function isStopChar(char)
+        {
+            return (char > " " && char < "0") ||
+                (char > "9" && char < "A") ||
+                (char > "Z" && char < "a") ||
+                (char > "z" && char <= "~");
+        }
+
+        /**
+         * @param {string} char
+         */
+        function isSpaceChar(char)
+        {
+            return char === "\t" || char === "\r" || char === "\n" || char === " ";
+        }
+
+        var lineNumber = selection.endLine;
+        var column = selection.endColumn;
+        if (direction === "left")
+            --column;
+
+        if (column === -1 && direction === "left") {
+            if (lineNumber > 0)
+                return new WebInspector.TextRange(selection.startLine, selection.startColumn, lineNumber - 1, this._textModel.line(lineNumber - 1).length);
+            else
+                return selection.clone();
+        }
+
+        var line = this._textModel.line(lineNumber);
+        if (column === line.length && direction === "right") {
+            if (lineNumber + 1 < this._textModel.linesCount)
+                return new WebInspector.TextRange(selection.startLine, selection.startColumn, selection.endLine + 1, 0);
+            else
+                return selection.clone();
+        }
+
+        var delta = direction === "left" ? -1 : +1;
+        var directionDependentEndColumnOffset = (delta + 1) / 2;
+
+        if (isSpaceChar(line.charAt(column))) {
+            while(column + delta >= 0 && column + delta < line.length && isSpaceChar(line.charAt(column + delta)))
+                column += delta;
+            if (column + delta < 0 || column + delta === line.length)
+                return new WebInspector.TextRange(selection.startLine, selection.startColumn, lineNumber, column + directionDependentEndColumnOffset);
+            else
+                column += delta;
+        }
+
+        var group = isStopChar(line.charAt(column));
+
+        while(column + delta >= 0 && column + delta < line.length && isStopChar(line.charAt(column + delta)) === group && !isSpaceChar(line.charAt(column + delta)))
+            column += delta;
+
+        return new WebInspector.TextRange(selection.startLine, selection.startColumn, lineNumber, column + directionDependentEndColumnOffset);
+    },
+
+    /**
+     * @param {string} direction
+     * @return {boolean}
+     */
+    _handleCtrlArrow: function(direction)
+    {
+        var newSelection = this._rangeForCtrlArrowMove(this._textEditor.selection(), direction);
+        this._textEditor.setSelection(newSelection.collapseToEnd());
+        return true;
+    },
+
+    /**
+     * @param {string} direction
+     * @return {boolean}
+     */
+    _handleCtrlShiftArrow: function(direction)
+    {
+        this._textEditor.setSelection(this._rangeForCtrlArrowMove(this._textEditor.selection(), direction));
+        return true;
+    },
+
+    /**
+     * @return {boolean}
+     */
+    _handleCtrlBackspace: function()
+    {
+        var selection = this._textEditor.selection();
+        if (!selection.isEmpty())
+            return false;
+
+        var newSelection = this._rangeForCtrlArrowMove(selection, "left");
+        this._textModel.editRange(newSelection.normalize(), "");
+
+        this._textEditor.setSelection(newSelection.collapseToEnd());
+        return true;
+    }
+}
+
 WebInspector.debugDefaultTextEditor = false;
index bd6a55b..8c04620 100644 (file)
@@ -151,7 +151,7 @@ WebInspector.TextEditor.prototype = {
     /**
      * @return {WebInspector.TextRange}
      */
-    selection: function(textRange) { },
+    selection: function() { },
 
     /**
      * @return {WebInspector.TextRange?}