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)); |
91 this._codeMirror.on("cursorActivity", this._cursorActivity.bind(this)); | 100 this._codeMirror.on("cursorActivity", this._cursorActivity.bind(this)); |
92 this._codeMirror.on("scroll", this._scroll.bind(this)); | 101 this._codeMirror.on("scroll", this._scroll.bind(this)); |
93 this.element.addEventListener("contextmenu", this._contextMenu.bind(this)); | 102 this.element.addEventListener("contextmenu", this._contextMenu.bind(this)); |
94 | 103 |
95 this.element.firstChild.addStyleClass("source-code"); | 104 this.element.firstChild.addStyleClass("source-code"); |
96 this.element.firstChild.addStyleClass("fill"); | 105 this.element.firstChild.addStyleClass("fill"); |
97 this._elementToWidget = new Map(); | 106 this._elementToWidget = new Map(); |
98 this._nestedUpdatesCounter = 0; | 107 this._nestedUpdatesCounter = 0; |
99 | 108 |
100 this.element.addEventListener("focus", this._handleElementFocus.bind(this),
false); | 109 this.element.addEventListener("focus", this._handleElementFocus.bind(this),
false); |
| 110 this.element.addEventListener("keydown", this._handleKeyDown.bind(this), fal
se); |
101 this.element.tabIndex = 0; | 111 this.element.tabIndex = 0; |
102 this._setupSelectionColor(); | 112 this._setupSelectionColor(); |
103 } | 113 } |
104 | 114 |
105 WebInspector.CodeMirrorTextEditor.prototype = { | 115 WebInspector.CodeMirrorTextEditor.prototype = { |
106 | 116 |
107 undo: function() | 117 undo: function() |
108 { | 118 { |
109 this._codeMirror.undo(); | 119 this._codeMirror.undo(); |
110 }, | 120 }, |
(...skipping 13 matching lines...) Expand all Loading... |
124 var foregroundColor = WebInspector.getSelectionForegroundColor(); | 134 var foregroundColor = WebInspector.getSelectionForegroundColor(); |
125 var foregroundColorRule = foregroundColor ? ".CodeMirror .CodeMirror-sel
ectedtext { color: " + foregroundColor + "!important;}" : ""; | 135 var foregroundColorRule = foregroundColor ? ".CodeMirror .CodeMirror-sel
ectedtext { color: " + foregroundColor + "!important;}" : ""; |
126 if (!foregroundColorRule && !backgroundColorRule) | 136 if (!foregroundColorRule && !backgroundColorRule) |
127 return; | 137 return; |
128 | 138 |
129 var style = document.createElement("style"); | 139 var style = document.createElement("style"); |
130 style.textContent = backgroundColorRule + foregroundColorRule; | 140 style.textContent = backgroundColorRule + foregroundColorRule; |
131 document.head.appendChild(style); | 141 document.head.appendChild(style); |
132 }, | 142 }, |
133 | 143 |
| 144 _autocomplete: function(codeMirror) |
| 145 { |
| 146 var cursor = codeMirror.getCursor(); |
| 147 var prefixRange = this._wordRangeForCursorPosition(cursor.line, cursor.c
h, true); |
| 148 if (!prefixRange) |
| 149 return null; |
| 150 var prefix = this.copyRange(prefixRange); |
| 151 this._dictionary.removeWord(prefix); |
| 152 var wordsWithPrefix = this._dictionary.wordsWithPrefix(this.copyRange(pr
efixRange)); |
| 153 this._dictionary.addWord(prefix); |
| 154 |
| 155 var data = { |
| 156 list: wordsWithPrefix, |
| 157 from: new CodeMirror.Pos(prefixRange.startLine, prefixRange.startCol
umn), |
| 158 to: new CodeMirror.Pos(prefixRange.endLine, prefixRange.endColumn) |
| 159 }; |
| 160 CodeMirror.on(data, "close", this._handleAutocompletionClose.bind(this))
; |
| 161 |
| 162 return data; |
| 163 }, |
| 164 |
| 165 _handleKeyDown: function(e) |
| 166 { |
| 167 if (!!this._consumeEsc && e.keyCode === WebInspector.KeyboardShortcut.Ke
ys.Esc.code) |
| 168 e.consume(true); |
| 169 delete this._consumeEsc; |
| 170 }, |
| 171 |
| 172 _handleAutocompletionClose: function() |
| 173 { |
| 174 this._consumeEsc = true; |
| 175 }, |
| 176 |
| 177 /** |
| 178 * @param {string} text |
| 179 */ |
| 180 _addTextToCompletionDictionary: function(text) |
| 181 { |
| 182 var words = WebInspector.TextUtils.textToWords(text); |
| 183 for(var i = 0; i < words.length; ++i) { |
| 184 this._dictionary.addWord(words[i]); |
| 185 } |
| 186 }, |
| 187 |
| 188 /** |
| 189 * @param {string} text |
| 190 */ |
| 191 _removeTextFromCompletionDictionary: function(text) |
| 192 { |
| 193 var words = WebInspector.TextUtils.textToWords(text); |
| 194 for(var i = 0; i < words.length; ++i) { |
| 195 this._dictionary.removeWord(words[i]); |
| 196 } |
| 197 }, |
| 198 |
134 /** | 199 /** |
135 * @param {WebInspector.CompletionDictionary} dictionary | 200 * @param {WebInspector.CompletionDictionary} dictionary |
136 */ | 201 */ |
137 setCompletionDictionary: function(dictionary) { }, | 202 setCompletionDictionary: function(dictionary) |
| 203 { |
| 204 this._dictionary = dictionary; |
| 205 this._addTextToCompletionDictionary(this.text()); |
| 206 }, |
138 | 207 |
139 /** | 208 /** |
140 * @param {number} lineNumber | 209 * @param {number} lineNumber |
141 * @param {number} column | 210 * @param {number} column |
142 * @return {?{x: number, y: number, height: number}} | 211 * @return {?{x: number, y: number, height: number}} |
143 */ | 212 */ |
144 cursorPositionToCoordinates: function(lineNumber, column) | 213 cursorPositionToCoordinates: function(lineNumber, column) |
145 { | 214 { |
146 if (lineNumber >= this._codeMirror.lineCount || column > this._codeMirro
r.getLine(lineNumber).length || lineNumber < 0 || column < 0) | 215 if (lineNumber >= this._codeMirror.lineCount || column > this._codeMirro
r.getLine(lineNumber).length || lineNumber < 0 || column < 0) |
147 return null; | 216 return null; |
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
487 */ | 556 */ |
488 editRange: function(range, text) | 557 editRange: function(range, text) |
489 { | 558 { |
490 var pos = this._toPos(range); | 559 var pos = this._toPos(range); |
491 this._codeMirror.replaceRange(text, pos.start, pos.end); | 560 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)); | 561 var newRange = this._toRange(pos.start, this._codeMirror.posFromIndex(th
is._codeMirror.indexFromPos(pos.start) + text.length)); |
493 this._delegate.onTextChanged(range, newRange); | 562 this._delegate.onTextChanged(range, newRange); |
494 return newRange; | 563 return newRange; |
495 }, | 564 }, |
496 | 565 |
| 566 /** |
| 567 * @param {number} lineNumber |
| 568 * @param {number} column |
| 569 * @param {boolean=} prefixOnly |
| 570 * @return {?WebInspector.TextRange} |
| 571 */ |
| 572 _wordRangeForCursorPosition: function(lineNumber, column, prefixOnly) |
| 573 { |
| 574 var line = this.line(lineNumber); |
| 575 if (!WebInspector.TextUtils.isWordChar(line.charAt(column - 1))) |
| 576 return null; |
| 577 var wordStart = column - 1; |
| 578 while(wordStart > 0 && WebInspector.TextUtils.isWordChar(line.charAt(wor
dStart - 1))) |
| 579 --wordStart; |
| 580 if (prefixOnly) |
| 581 return new WebInspector.TextRange(lineNumber, wordStart, lineNumber,
column); |
| 582 var wordEnd = column; |
| 583 while(wordEnd < line.length && WebInspector.TextUtils.isWordChar(line.ch
arAt(wordEnd))) |
| 584 ++wordEnd; |
| 585 return new WebInspector.TextRange(lineNumber, wordStart, lineNumber, wor
dEnd); |
| 586 }, |
| 587 |
| 588 _beforeChange: function(codeMirror, changeObject) |
| 589 { |
| 590 if (!this._dictionary) |
| 591 return; |
| 592 this._updatedLines = this._updatedLines || {}; |
| 593 for(var i = changeObject.from.line; i <= changeObject.to.line; ++i) |
| 594 this._updatedLines[i] = this.line(i); |
| 595 }, |
| 596 |
497 _change: function(codeMirror, changeObject) | 597 _change: function(codeMirror, changeObject) |
498 { | 598 { |
499 var widgets = this._elementToWidget.values(); | 599 var widgets = this._elementToWidget.values(); |
500 for (var i = 0; i < widgets.length; ++i) | 600 for (var i = 0; i < widgets.length; ++i) |
501 this._codeMirror.removeLineWidget(widgets[i]); | 601 this._codeMirror.removeLineWidget(widgets[i]); |
502 this._elementToWidget.clear(); | 602 this._elementToWidget.clear(); |
503 | 603 |
| 604 if (this._updatedLines) { |
| 605 for(var lineNumber in this._updatedLines) |
| 606 this._removeTextFromCompletionDictionary(this._updatedLines[line
Number]); |
| 607 delete this._updatedLines; |
| 608 } |
| 609 |
| 610 var linesToUpdate = {}; |
504 do { | 611 do { |
505 var oldRange = this._toRange(changeObject.from, changeObject.to); | 612 var oldRange = this._toRange(changeObject.from, changeObject.to); |
506 var newRange = oldRange.clone(); | 613 var newRange = oldRange.clone(); |
507 var linesAdded = changeObject.text.length; | 614 var linesAdded = changeObject.text.length; |
508 if (linesAdded === 0) { | 615 if (linesAdded === 0) { |
509 newRange.endLine = newRange.startLine; | 616 newRange.endLine = newRange.startLine; |
510 newRange.endColumn = newRange.startColumn; | 617 newRange.endColumn = newRange.startColumn; |
511 } else if (linesAdded === 1) { | 618 } else if (linesAdded === 1) { |
512 newRange.endLine = newRange.startLine; | 619 newRange.endLine = newRange.startLine; |
513 newRange.endColumn = newRange.startColumn + changeObject.text[0]
.length; | 620 newRange.endColumn = newRange.startColumn + changeObject.text[0]
.length; |
514 } else { | 621 } else { |
515 newRange.endLine = newRange.startLine + linesAdded - 1; | 622 newRange.endLine = newRange.startLine + linesAdded - 1; |
516 newRange.endColumn = changeObject.text[linesAdded - 1].length; | 623 newRange.endColumn = changeObject.text[linesAdded - 1].length; |
517 } | 624 } |
518 | 625 |
519 if (!this._muteTextChangedEvent) | 626 if (!this._muteTextChangedEvent) |
520 this._delegate.onTextChanged(oldRange, newRange); | 627 this._delegate.onTextChanged(oldRange, newRange); |
521 | 628 |
| 629 for(var i = newRange.startLine; i <= newRange.endLine; ++i) { |
| 630 linesToUpdate[i] = true; |
| 631 } |
| 632 if (this._dictionary) { |
| 633 for(var i = newRange.startLine; i <= newRange.endLine; ++i) |
| 634 linesToUpdate[i] = this.line(i); |
| 635 } |
522 } while (changeObject = changeObject.next); | 636 } while (changeObject = changeObject.next); |
| 637 if (this._dictionary) { |
| 638 for(var lineNumber in linesToUpdate) |
| 639 this._addTextToCompletionDictionary(linesToUpdate[lineNumber]); |
| 640 } |
523 }, | 641 }, |
524 | 642 |
525 _cursorActivity: function() | 643 _cursorActivity: function() |
526 { | 644 { |
527 var start = this._codeMirror.getCursor("anchor"); | 645 var start = this._codeMirror.getCursor("anchor"); |
528 var end = this._codeMirror.getCursor("head"); | 646 var end = this._codeMirror.getCursor("head"); |
529 this._delegate.selectionChanged(this._toRange(start, end)); | 647 this._delegate.selectionChanged(this._toRange(start, end)); |
530 }, | 648 }, |
531 | 649 |
532 _coordsCharLocal: function(coords) | 650 _coordsCharLocal: function(coords) |
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
874 var modifierKey = WebInspector.isMac() ? "Alt" : "Ctrl"; | 992 var modifierKey = WebInspector.isMac() ? "Alt" : "Ctrl"; |
875 var leftKey = modifierKey + "-Left"; | 993 var leftKey = modifierKey + "-Left"; |
876 var rightKey = modifierKey + "-Right"; | 994 var rightKey = modifierKey + "-Right"; |
877 var keyMap = {}; | 995 var keyMap = {}; |
878 keyMap[leftKey] = moveLeft.bind(this, false); | 996 keyMap[leftKey] = moveLeft.bind(this, false); |
879 keyMap[rightKey] = moveRight.bind(this, false); | 997 keyMap[rightKey] = moveRight.bind(this, false); |
880 keyMap["Shift-" + leftKey] = moveLeft.bind(this, true); | 998 keyMap["Shift-" + leftKey] = moveLeft.bind(this, true); |
881 keyMap["Shift-" + rightKey] = moveRight.bind(this, true); | 999 keyMap["Shift-" + rightKey] = moveRight.bind(this, true); |
882 codeMirror.addKeyMap(keyMap); | 1000 codeMirror.addKeyMap(keyMap); |
883 } | 1001 } |
OLD | NEW |