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 |