Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2012 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 48 WebInspector.CodeMirrorTextEditor = function(url, delegate) | 48 WebInspector.CodeMirrorTextEditor = function(url, delegate) |
| 49 { | 49 { |
| 50 WebInspector.View.call(this); | 50 WebInspector.View.call(this); |
| 51 this._delegate = delegate; | 51 this._delegate = delegate; |
| 52 this._url = url; | 52 this._url = url; |
| 53 | 53 |
| 54 this.registerRequiredCSS("cm/codemirror.css"); | 54 this.registerRequiredCSS("cm/codemirror.css"); |
| 55 this.registerRequiredCSS("cm/showhint.css"); | 55 this.registerRequiredCSS("cm/showhint.css"); |
| 56 this.registerRequiredCSS("cm/cmdevtools.css"); | 56 this.registerRequiredCSS("cm/cmdevtools.css"); |
| 57 | 57 |
| 58 function autocompleteCommand() | |
| 59 { | |
| 60 if (!this._dictionary || this._codeMirror.somethingSelected()) | |
| 61 return; | |
| 62 CodeMirror.showHint(this._codeMirror, this._autocomplete.bind(this)); | |
| 63 } | |
| 64 CodeMirror.commands.autocomplete = autocompleteCommand.bind(this); | |
| 65 | |
| 58 this._codeMirror = window.CodeMirror(this.element, { | 66 this._codeMirror = window.CodeMirror(this.element, { |
| 59 lineNumbers: true, | 67 lineNumbers: true, |
| 60 gutters: ["CodeMirror-linenumbers"], | 68 gutters: ["CodeMirror-linenumbers"], |
| 61 matchBrackets: true, | 69 matchBrackets: true, |
| 62 smartIndent: false, | 70 smartIndent: false, |
| 63 styleSelectedText: true, | 71 styleSelectedText: true, |
| 64 electricChars: false, | 72 electricChars: false, |
| 65 autoCloseBrackets: true | 73 autoCloseBrackets: true |
| 66 }); | 74 }); |
| 67 | 75 |
| 68 var extraKeys = {}; | 76 var extraKeys = {"Ctrl-Space": "autocomplete"}; |
| 69 var indent = WebInspector.settings.textEditorIndent.get(); | 77 var indent = WebInspector.settings.textEditorIndent.get(); |
| 70 if (indent === WebInspector.TextUtils.Indent.TabCharacter) { | 78 if (indent === WebInspector.TextUtils.Indent.TabCharacter) { |
| 71 this._codeMirror.setOption("indentWithTabs", true); | 79 this._codeMirror.setOption("indentWithTabs", true); |
| 72 this._codeMirror.setOption("indentUnit", 4); | 80 this._codeMirror.setOption("indentUnit", 4); |
| 73 } else { | 81 } else { |
| 74 this._codeMirror.setOption("indentWithTabs", false); | 82 this._codeMirror.setOption("indentWithTabs", false); |
| 75 this._codeMirror.setOption("indentUnit", indent.length); | 83 this._codeMirror.setOption("indentUnit", indent.length); |
| 76 extraKeys.Tab = function(codeMirror) | 84 extraKeys.Tab = function(codeMirror) |
| 77 { | 85 { |
| 78 if (codeMirror.somethingSelected()) | 86 if (codeMirror.somethingSelected()) |
| 79 return CodeMirror.Pass; | 87 return CodeMirror.Pass; |
| 80 codeMirror.replaceRange(indent, codeMirror.getCursor()); | 88 codeMirror.replaceRange(indent, codeMirror.getCursor()); |
| 81 } | 89 } |
| 82 } | 90 } |
| 83 this._codeMirror.setOption("extraKeys", extraKeys); | 91 this._codeMirror.setOption("extraKeys", extraKeys); |
| 84 | 92 |
| 85 this._tokenHighlighter = new WebInspector.CodeMirrorTextEditor.TokenHighligh ter(this._codeMirror); | 93 this._tokenHighlighter = new WebInspector.CodeMirrorTextEditor.TokenHighligh ter(this._codeMirror); |
| 86 this._blockIndentController = new WebInspector.CodeMirrorTextEditor.BlockInd entController(this._codeMirror); | 94 this._blockIndentController = new WebInspector.CodeMirrorTextEditor.BlockInd entController(this._codeMirror); |
| 87 this._fixWordMovement = new WebInspector.CodeMirrorTextEditor.FixWordMovemen t(this._codeMirror); | 95 this._fixWordMovement = new WebInspector.CodeMirrorTextEditor.FixWordMovemen t(this._codeMirror); |
| 88 | 96 |
| 89 this._codeMirror.on("change", this._change.bind(this)); | 97 this._codeMirror.on("change", this._change.bind(this)); |
| 98 this._codeMirror.on("beforeChange", this._beforeChange.bind(this)); | |
| 90 this._codeMirror.on("gutterClick", this._gutterClick.bind(this)); | 99 this._codeMirror.on("gutterClick", this._gutterClick.bind(this)); |
| 100 | |
|
vsevik
2013/05/24 16:32:34
extra line
| |
| 91 this._codeMirror.on("cursorActivity", this._cursorActivity.bind(this)); | 101 this._codeMirror.on("cursorActivity", this._cursorActivity.bind(this)); |
| 92 this._codeMirror.on("scroll", this._scroll.bind(this)); | 102 this._codeMirror.on("scroll", this._scroll.bind(this)); |
| 93 this.element.addEventListener("contextmenu", this._contextMenu.bind(this)); | 103 this.element.addEventListener("contextmenu", this._contextMenu.bind(this)); |
| 94 | 104 |
| 95 this.element.firstChild.addStyleClass("source-code"); | 105 this.element.firstChild.addStyleClass("source-code"); |
| 96 this.element.firstChild.addStyleClass("fill"); | 106 this.element.firstChild.addStyleClass("fill"); |
| 97 this._elementToWidget = new Map(); | 107 this._elementToWidget = new Map(); |
| 98 this._nestedUpdatesCounter = 0; | 108 this._nestedUpdatesCounter = 0; |
| 99 | 109 |
| 100 this.element.addEventListener("focus", this._handleElementFocus.bind(this), false); | 110 this.element.addEventListener("focus", this._handleElementFocus.bind(this), false); |
| 111 this.element.addEventListener("keydown", this._handleKeyDown.bind(this), fal se); | |
| 101 this.element.tabIndex = 0; | 112 this.element.tabIndex = 0; |
| 102 this._setupSelectionColor(); | 113 this._setupSelectionColor(); |
| 103 } | 114 } |
| 104 | 115 |
| 105 WebInspector.CodeMirrorTextEditor.prototype = { | 116 WebInspector.CodeMirrorTextEditor.prototype = { |
| 106 | 117 |
| 107 undo: function() | 118 undo: function() |
| 108 { | 119 { |
| 109 this._codeMirror.undo(); | 120 this._codeMirror.undo(); |
| 110 }, | 121 }, |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 124 var foregroundColor = WebInspector.getSelectionForegroundColor(); | 135 var foregroundColor = WebInspector.getSelectionForegroundColor(); |
| 125 var foregroundColorRule = foregroundColor ? ".CodeMirror .CodeMirror-sel ectedtext { color: " + foregroundColor + "!important;}" : ""; | 136 var foregroundColorRule = foregroundColor ? ".CodeMirror .CodeMirror-sel ectedtext { color: " + foregroundColor + "!important;}" : ""; |
| 126 if (!foregroundColorRule && !backgroundColorRule) | 137 if (!foregroundColorRule && !backgroundColorRule) |
| 127 return; | 138 return; |
| 128 | 139 |
| 129 var style = document.createElement("style"); | 140 var style = document.createElement("style"); |
| 130 style.textContent = backgroundColorRule + foregroundColorRule; | 141 style.textContent = backgroundColorRule + foregroundColorRule; |
| 131 document.head.appendChild(style); | 142 document.head.appendChild(style); |
| 132 }, | 143 }, |
| 133 | 144 |
| 145 _autocomplete: function(codeMirror) | |
| 146 { | |
| 147 var cursor = codeMirror.getCursor(); | |
| 148 var prefixRange = this._wordRangeForCursorPosition(cursor.line, cursor.c h, true); | |
| 149 if (!prefixRange) | |
| 150 return null; | |
| 151 var prefix = this.copyRange(prefixRange); | |
| 152 this._dictionary.removeWord(prefix); | |
| 153 var wordsWithPrefix = this._dictionary.wordsWithPrefix(this.copyRange(pr efixRange)); | |
| 154 this._dictionary.addWord(prefix); | |
| 155 | |
| 156 var data = { | |
| 157 list: wordsWithPrefix, | |
| 158 from: new CodeMirror.Pos(prefixRange.startLine, prefixRange.startCol umn), | |
| 159 to: new CodeMirror.Pos(prefixRange.endLine, prefixRange.endColumn) | |
| 160 }; | |
| 161 CodeMirror.on(data, "close", this._handleAutocompletionClose.bind(this)) ; | |
| 162 | |
| 163 return data; | |
| 164 }, | |
| 165 | |
| 166 _handleKeyDown: function(e) | |
| 167 { | |
| 168 if (!!this._consumeEsc && e.keyCode === WebInspector.KeyboardShortcut.Ke ys.Esc.code) | |
| 169 e.consume(true); | |
| 170 delete this._consumeEsc; | |
| 171 }, | |
| 172 | |
| 173 _handleAutocompletionClose: function() | |
| 174 { | |
| 175 this._consumeEsc = true; | |
| 176 }, | |
| 177 | |
| 178 /** | |
| 179 * @param {string} text | |
| 180 */ | |
| 181 _addTextToCompletionDictionary: function(text) | |
| 182 { | |
| 183 var words = WebInspector.TextUtils.textToWords(text); | |
| 184 for(var i = 0; i < words.length; ++i) { | |
| 185 this._dictionary.addWord(words[i]); | |
| 186 } | |
| 187 }, | |
| 188 | |
| 189 /** | |
| 190 * @param {string} text | |
| 191 */ | |
| 192 _removeTextFromCompletionDictionary: function(text) | |
| 193 { | |
| 194 var words = WebInspector.TextUtils.textToWords(text); | |
| 195 for(var i = 0; i < words.length; ++i) { | |
| 196 this._dictionary.removeWord(words[i]); | |
| 197 } | |
| 198 }, | |
| 199 | |
| 134 /** | 200 /** |
| 135 * @param {WebInspector.CompletionDictionary} dictionary | 201 * @param {WebInspector.CompletionDictionary} dictionary |
| 136 */ | 202 */ |
| 137 setCompletionDictionary: function(dictionary) { }, | 203 setCompletionDictionary: function(dictionary) |
| 204 { | |
| 205 this._dictionary = dictionary; | |
| 206 this._addTextToCompletionDictionary(this.text()); | |
| 207 }, | |
| 138 | 208 |
| 139 /** | 209 /** |
| 140 * @param {number} lineNumber | 210 * @param {number} lineNumber |
| 141 * @param {number} column | 211 * @param {number} column |
| 142 * @return {?{x: number, y: number, height: number}} | 212 * @return {?{x: number, y: number, height: number}} |
| 143 */ | 213 */ |
| 144 cursorPositionToCoordinates: function(lineNumber, column) | 214 cursorPositionToCoordinates: function(lineNumber, column) |
| 145 { | 215 { |
| 146 if (lineNumber >= this._codeMirror.lineCount || column > this._codeMirro r.getLine(lineNumber).length || lineNumber < 0 || column < 0) | 216 if (lineNumber >= this._codeMirror.lineCount || column > this._codeMirro r.getLine(lineNumber).length || lineNumber < 0 || column < 0) |
| 147 return null; | 217 return null; |
| (...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 487 */ | 557 */ |
| 488 editRange: function(range, text) | 558 editRange: function(range, text) |
| 489 { | 559 { |
| 490 var pos = this._toPos(range); | 560 var pos = this._toPos(range); |
| 491 this._codeMirror.replaceRange(text, pos.start, pos.end); | 561 this._codeMirror.replaceRange(text, pos.start, pos.end); |
| 492 var newRange = this._toRange(pos.start, this._codeMirror.posFromIndex(th is._codeMirror.indexFromPos(pos.start) + text.length)); | 562 var newRange = this._toRange(pos.start, this._codeMirror.posFromIndex(th is._codeMirror.indexFromPos(pos.start) + text.length)); |
| 493 this._delegate.onTextChanged(range, newRange); | 563 this._delegate.onTextChanged(range, newRange); |
| 494 return newRange; | 564 return newRange; |
| 495 }, | 565 }, |
| 496 | 566 |
| 567 /** | |
| 568 * @param {number} lineNumber | |
| 569 * @param {number} column | |
| 570 * @param {boolean=} prefixOnly | |
| 571 * @return {?WebInspector.TextRange} | |
| 572 */ | |
| 573 _wordRangeForCursorPosition: function(lineNumber, column, prefixOnly) | |
| 574 { | |
| 575 var line = this.line(lineNumber); | |
| 576 if (!WebInspector.TextUtils.isWordChar(line.charAt(column - 1))) | |
| 577 return null; | |
| 578 var wordStart = column - 1; | |
| 579 while(wordStart > 0 && WebInspector.TextUtils.isWordChar(line.charAt(wor dStart - 1))) | |
| 580 --wordStart; | |
| 581 if (prefixOnly) | |
| 582 return new WebInspector.TextRange(lineNumber, wordStart, lineNumber, column); | |
| 583 var wordEnd = column; | |
| 584 while(wordEnd < line.length && WebInspector.TextUtils.isWordChar(line.ch arAt(wordEnd))) | |
| 585 ++wordEnd; | |
| 586 return new WebInspector.TextRange(lineNumber, wordStart, lineNumber, wor dEnd); | |
| 587 }, | |
| 588 | |
| 589 _beforeChange: function(codeMirror, changeObject) | |
| 590 { | |
| 591 if (!this._dictionary) | |
| 592 return; | |
| 593 this._updatedLines = this._updatedLines || {}; | |
| 594 for(var i = changeObject.from.line; i <= changeObject.to.line; ++i) | |
| 595 this._updatedLines[i] = this.line(i); | |
| 596 }, | |
| 597 | |
| 497 _change: function(codeMirror, changeObject) | 598 _change: function(codeMirror, changeObject) |
| 498 { | 599 { |
| 499 var widgets = this._elementToWidget.values(); | 600 var widgets = this._elementToWidget.values(); |
| 500 for (var i = 0; i < widgets.length; ++i) | 601 for (var i = 0; i < widgets.length; ++i) |
| 501 this._codeMirror.removeLineWidget(widgets[i]); | 602 this._codeMirror.removeLineWidget(widgets[i]); |
| 502 this._elementToWidget.clear(); | 603 this._elementToWidget.clear(); |
| 503 | 604 |
| 605 if (this._updatedLines) { | |
| 606 for(var lineNumber in this._updatedLines) | |
| 607 this._removeTextFromCompletionDictionary(this._updatedLines[line Number]); | |
| 608 delete this._updatedLines; | |
| 609 } | |
| 610 | |
| 611 var linesToUpdate = {}; | |
| 504 do { | 612 do { |
| 505 var oldRange = this._toRange(changeObject.from, changeObject.to); | 613 var oldRange = this._toRange(changeObject.from, changeObject.to); |
| 506 var newRange = oldRange.clone(); | 614 var newRange = oldRange.clone(); |
| 507 var linesAdded = changeObject.text.length; | 615 var linesAdded = changeObject.text.length; |
| 508 if (linesAdded === 0) { | 616 if (linesAdded === 0) { |
| 509 newRange.endLine = newRange.startLine; | 617 newRange.endLine = newRange.startLine; |
| 510 newRange.endColumn = newRange.startColumn; | 618 newRange.endColumn = newRange.startColumn; |
| 511 } else if (linesAdded === 1) { | 619 } else if (linesAdded === 1) { |
| 512 newRange.endLine = newRange.startLine; | 620 newRange.endLine = newRange.startLine; |
| 513 newRange.endColumn = newRange.startColumn + changeObject.text[0] .length; | 621 newRange.endColumn = newRange.startColumn + changeObject.text[0] .length; |
| 514 } else { | 622 } else { |
| 515 newRange.endLine = newRange.startLine + linesAdded - 1; | 623 newRange.endLine = newRange.startLine + linesAdded - 1; |
| 516 newRange.endColumn = changeObject.text[linesAdded - 1].length; | 624 newRange.endColumn = changeObject.text[linesAdded - 1].length; |
| 517 } | 625 } |
| 518 | 626 |
| 519 if (!this._muteTextChangedEvent) | 627 if (!this._muteTextChangedEvent) |
| 520 this._delegate.onTextChanged(oldRange, newRange); | 628 this._delegate.onTextChanged(oldRange, newRange); |
| 521 | 629 |
| 630 for(var i = newRange.startLine; i <= newRange.endLine; ++i) { | |
| 631 linesToUpdate[i] = true; | |
| 632 } | |
| 633 if (this._dictionary) { | |
| 634 for(var i = newRange.startLine; i <= newRange.endLine; ++i) | |
| 635 linesToUpdate[i] = this.line(i); | |
| 636 } | |
| 522 } while (changeObject = changeObject.next); | 637 } while (changeObject = changeObject.next); |
| 638 if (this._dictionary) { | |
| 639 for(var lineNumber in linesToUpdate) | |
| 640 this._addTextToCompletionDictionary(linesToUpdate[lineNumber]); | |
| 641 } | |
| 523 }, | 642 }, |
| 524 | 643 |
| 525 _cursorActivity: function() | 644 _cursorActivity: function() |
| 526 { | 645 { |
| 527 var start = this._codeMirror.getCursor("anchor"); | 646 var start = this._codeMirror.getCursor("anchor"); |
| 528 var end = this._codeMirror.getCursor("head"); | 647 var end = this._codeMirror.getCursor("head"); |
| 529 this._delegate.selectionChanged(this._toRange(start, end)); | 648 this._delegate.selectionChanged(this._toRange(start, end)); |
| 530 }, | 649 }, |
| 531 | 650 |
| 532 _coordsCharLocal: function(coords) | 651 _coordsCharLocal: function(coords) |
| (...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 874 var modifierKey = WebInspector.isMac() ? "Alt" : "Ctrl"; | 993 var modifierKey = WebInspector.isMac() ? "Alt" : "Ctrl"; |
| 875 var leftKey = modifierKey + "-Left"; | 994 var leftKey = modifierKey + "-Left"; |
| 876 var rightKey = modifierKey + "-Right"; | 995 var rightKey = modifierKey + "-Right"; |
| 877 var keyMap = {}; | 996 var keyMap = {}; |
| 878 keyMap[leftKey] = moveLeft.bind(this, false); | 997 keyMap[leftKey] = moveLeft.bind(this, false); |
| 879 keyMap[rightKey] = moveRight.bind(this, false); | 998 keyMap[rightKey] = moveRight.bind(this, false); |
| 880 keyMap["Shift-" + leftKey] = moveLeft.bind(this, true); | 999 keyMap["Shift-" + leftKey] = moveLeft.bind(this, true); |
| 881 keyMap["Shift-" + rightKey] = moveRight.bind(this, true); | 1000 keyMap["Shift-" + rightKey] = moveRight.bind(this, true); |
| 882 codeMirror.addKeyMap(keyMap); | 1001 codeMirror.addKeyMap(keyMap); |
| 883 } | 1002 } |
| OLD | NEW |