Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Side by Side Diff: Source/devtools/front_end/CodeMirrorTextEditor.js

Issue 15986003: DevTools: [CodeMirror] autocompletion for CodeMirrorTextEditor (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | Source/devtools/front_end/CompletionDictionary.js » ('j') | Source/devtools/front_end/JavaScriptSourceFrame.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698