• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

codemirror/H03-May-2022-741636

test/H03-May-2022-390349

READMEH A D30-Mar-20229.9 KiB239216

moz.buildH A D30-Mar-2022547 1915

package.jsonH A D30-Mar-2022367 1616

README

1This is the CodeMirror editor packaged for the Mozilla Project. CodeMirror
2is a JavaScript component that provides a code editor in the browser. When
3a mode is available for the language you are coding in, it will color your
4code, and optionally help with indentation.
5
6# Upgrade
7
8Currently used version is 5.58.1. To upgrade: download a new version of
9CodeMirror from the project's page [1] and replace all JavaScript and
10CSS files inside the codemirror directory [2].
11
12Then to recreate codemirror.bundle.js:
13 > cd devtools/client/shared/sourceeditor
14 > npm install
15 > npm run build
16
17When investigating an issue in CodeMirror, you might want to have a non-minified bundle.
18You can do this by running `npm run build-unminified` instead of `npm run build`.
19
20To confirm the functionality run mochitests for the following components:
21
22 * sourceeditor
23 * debugger
24 * styleditor
25 * netmonitor
26 * webconsole
27
28The sourceeditor component contains imported CodeMirror tests [3].
29
30 * Some tests were commented out because we don't use that functionality
31   within Firefox (for example Ruby editing mode). Be careful when updating
32   files test/codemirror.html and test/vimemacs.html; they were modified to
33   co-exist with Mozilla's testing infrastructure. Basically, vimemacs.html
34   is a copy of codemirror.html but only with VIM and Emacs mode tests
35   enabled.
36 * In cm_comment_test.js comment out fallbackToBlock and fallbackToLine
37   tests.
38 * The search addon (search.js) was slightly modified to make search
39   UI localizable (see patch below).
40
41Other than that, we don't have any Mozilla-specific patches applied to
42CodeMirror itself.
43
44# Addons
45
46To install a new CodeMirror addon add it to the codemirror directory,
47jar.mn [4] file and editor.js [5]. Also, add it to the License section
48below.
49
50# License
51
52The following files in this directory and devtools/client/shared/sourceeditor/test/codemirror/
53are licensed according to the contents in the LICENSE file.
54
55# Localization patches
56
57diff --git a/devtools/client/shared/sourceeditor/codemirror/addon/search/search.js b/devtools/client/shared/sourceeditor/codemirror/addon/search/search.js
58--- a/devtools/client/shared/sourceeditor/codemirror/addon/search/search.js
59+++ b/devtools/client/shared/sourceeditor/codemirror/addon/search/search.js
60@@ -93,32 +93,47 @@
61     } else {
62       query = parseString(query)
63     }
64     if (typeof query == "string" ? query == "" : query.test(""))
65       query = /x^/;
66     return query;
67   }
68
69-  var queryDialog =
70-    '<span class="CodeMirror-search-label">Search:</span> <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
71+  var queryDialog;
72
73   function startSearch(cm, state, query) {
74     state.queryText = query;
75     state.query = parseQuery(query);
76     cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
77     state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
78     cm.addOverlay(state.overlay);
79     if (cm.showMatchesOnScrollbar) {
80       if (state.annotate) { state.annotate.clear(); state.annotate = null; }
81       state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
82     }
83   }
84
85   function doSearch(cm, rev, persistent, immediate) {
86+    if (!queryDialog) {
87+      let doc = cm.getWrapperElement().ownerDocument;
88+      let inp = doc.createElement("input");
89+
90+      inp.type = "search";
91+      inp.placeholder = cm.l10n("findCmd.promptMessage");
92+      inp.style.marginInlineStart = "1em";
93+      inp.style.marginInlineEnd = "1em";
94+      inp.style.flexGrow = "1";
95+      inp.addEventListener("focus", () => inp.select());
96+
97+      queryDialog = doc.createElement("div");
98+      queryDialog.appendChild(inp);
99+      queryDialog.style.display = "flex";
100+    }
101+
102     var state = getSearchState(cm);
103     if (state.query) return findNext(cm, rev);
104     var q = cm.getSelection() || state.lastQuery;
105     if (q instanceof RegExp && q.source == "x^") q = null
106     if (persistent && cm.openDialog) {
107       var hiding = null
108       var searchNext = function(query, event) {
109         CodeMirror.e_stop(event);
110@@ -181,56 +196,110 @@
111     var state = getSearchState(cm);
112     state.lastQuery = state.query;
113     if (!state.query) return;
114     state.query = state.queryText = null;
115     cm.removeOverlay(state.overlay);
116     if (state.annotate) { state.annotate.clear(); state.annotate = null; }
117   });}
118
119-  var replaceQueryDialog =
120-    ' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
121-  var replacementQueryDialog = '<span class="CodeMirror-search-label">With:</span> <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
122-  var doReplaceConfirm = '<span class="CodeMirror-search-label">Replace?</span> <button>Yes</button> <button>No</button> <button>All</button> <button>Stop</button>';
123-
124   function replaceAll(cm, query, text) {
125     cm.operation(function() {
126       for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
127         if (typeof query != "string") {
128           var match = cm.getRange(cursor.from(), cursor.to()).match(query);
129           cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
130         } else cursor.replace(text);
131       }
132     });
133   }
134
135   function replace(cm, all) {
136     if (cm.getOption("readOnly")) return;
137     var query = cm.getSelection() || getSearchState(cm).lastQuery;
138-    var dialogText = '<span class="CodeMirror-search-label">' + (all ? 'Replace all:' : 'Replace:') + '</span>';
139-    dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) {
140+
141+    let doc = cm.getWrapperElement().ownerDocument;
142+
143+    // `searchLabel` is used as part of `replaceQueryFragment` and as a separate
144+    // argument by itself, so it should be cloned.
145+    let searchLabel = doc.createElement("span");
146+    searchLabel.classList.add("CodeMirror-search-label");
147+    searchLabel.textContent = all ? "Replace all:" : "Replace:";
148+
149+    let replaceQueryFragment = doc.createDocumentFragment();
150+    replaceQueryFragment.appendChild(searchLabel.cloneNode(true));
151+
152+    let searchField = doc.createElement("input");
153+    searchField.setAttribute("type", "text");
154+    searchField.setAttribute("style", "width: 10em");
155+    searchField.classList.add("CodeMirror-search-field");
156+    replaceQueryFragment.appendChild(searchField);
157+
158+    let searchHint = doc.createElement("span");
159+    searchHint.setAttribute("style", "color: #888");
160+    searchHint.classList.add("CodeMirror-search-hint");
161+    searchHint.textContent = "(Use /re/ syntax for regexp search)";
162+    replaceQueryFragment.appendChild(searchHint);
163+
164+    dialog(cm, replaceQueryFragment, searchLabel, query, function(query) {
165       if (!query) return;
166       query = parseQuery(query);
167-      dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
168+
169+      let replacementQueryFragment = doc.createDocumentFragment();
170+
171+      let replaceWithLabel = searchLabel.cloneNode(false);
172+      replaceWithLabel.textContent = "With:";
173+      replacementQueryFragment.appendChild(replaceWithLabel);
174+
175+      let replaceField = doc.createElement("input");
176+      replaceField.setAttribute("type", "text");
177+      replaceField.setAttribute("style", "width: 10em");
178+      replaceField.classList.add("CodeMirror-search-field");
179+      replacementQueryFragment.appendChild(replaceField);
180+
181+      dialog(cm, replacementQueryFragment, "Replace with:", "", function(text) {
182         text = parseString(text)
183         if (all) {
184           replaceAll(cm, query, text)
185         } else {
186           clearSearch(cm);
187           var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
188           var advance = function() {
189             var start = cursor.from(), match;
190             if (!(match = cursor.findNext())) {
191               cursor = getSearchCursor(cm, query);
192               if (!(match = cursor.findNext()) ||
193                   (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
194             }
195             cm.setSelection(cursor.from(), cursor.to());
196-            cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
197-            confirmDialog(cm, doReplaceConfirm, "Replace?",
198+            cm.scrollIntoView({ from: cursor.from(), to: cursor.to() });
199+
200+            let replaceConfirmFragment = doc.createDocumentFragment();
201+
202+            let replaceConfirmLabel = searchLabel.cloneNode(false);
203+            replaceConfirmLabel.textContent = "Replace?";
204+            replaceConfirmFragment.appendChild(replaceConfirmLabel);
205+
206+            let yesButton = doc.createElement("button");
207+            yesButton.textContent = "Yes";
208+            replaceConfirmFragment.appendChild(yesButton);
209+
210+            let noButton = doc.createElement("button");
211+            noButton.textContent = "No";
212+            replaceConfirmFragment.appendChild(noButton);
213+
214+            let allButton = doc.createElement("button");
215+            allButton.textContent = "All";
216+            replaceConfirmFragment.appendChild(allButton);
217+
218+            let stopButton = doc.createElement("button");
219+            stopButton.textContent = "Stop";
220+            replaceConfirmFragment.appendChild(stopButton);
221+
222+            confirmDialog(cm, replaceConfirmFragment, "Replace?",
223                           [function() {doReplace(match);}, advance,
224                            function() {replaceAll(cm, query, text)}]);
225           };
226           var doReplace = function(match) {
227             cursor.replace(typeof query == "string" ? text :
228                            text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
229             advance();
230           };
231
232# Footnotes
233
234[1] http://codemirror.net
235[2] devtools/client/shared/sourceeditor/codemirror
236[3] devtools/client/shared/sourceeditor/test/browser_codemirror.js
237[4] devtools/client/jar.mn
238[5] devtools/client/shared/sourceeditor/editor.js
239