gecko-dev/devtools/client/sourceeditor
Alexandre Poirot fc8714580a Bug 1485676 - Rename TabTarget.makeRemote to TabTarget.attach. r=jdescottes
Summary:
Now that all the "remoting" of this method has been moved to TargetFactory.createTargetForTab,
we should rename this method to what it does now. It mostly call attach requests
of the target actor and its child console actor.
It also "connect" the webextension target actor, but I would like to eventually move that
outside of TabTarget.attach, like makeRemote.

Depends On D4078

Reviewers: yulia!

Tags: #secure-revision

Bug #: 1485676

Differential Revision: https://phabricator.services.mozilla.com/D6161

MozReview-Commit-ID: KmFi1LIUBga
2018-09-24 09:52:57 -07:00
..
codemirror Bug 1486298 - Update CodeMirror to 5.44.0 and add ClojureScript syntax highlighting. r=bgrins 2018-08-26 22:20:53 -04:00
tern Bug 1458883 - Remove File.lastModifiedDate, r=qdot 2018-05-04 14:39:53 +02:00
test Bug 1485676 - Rename TabTarget.makeRemote to TabTarget.attach. r=jdescottes 2018-09-24 09:52:57 -07:00
.eslintrc.js Bug 1316096 - Change eslint configuration to use string values for rules instead of integers, making it easier for others who are reading the rules to know if a rule is set to off, warn, or error. r=mossop 2016-11-08 15:14:19 -05:00
autocomplete.js Bug 1480384 - Remove unused theme option for autocomplete-popup;r=nchevobbe 2018-08-02 15:05:50 +00:00
css-autocompleter.js Bug 1454696 - Run eslint --fix for prefer-const;r=yulia 2018-06-01 12:36:09 +02:00
debugger.js Bug 1454696 - Run eslint --fix for prefer-const;r=yulia 2018-06-01 12:36:09 +02:00
editor-commands-controller.js Bug 1454696 - Run eslint --fix for prefer-const;r=yulia 2018-06-01 12:36:09 +02:00
editor.js Bug 1491776 - Do not use markText to show the completion text; r=bgrins. 2018-09-18 19:22:01 +00:00
moz.build Bug 1469872 - update bugzilla products and components in moz.build files: devtools. r=nalexander 2018-06-20 21:34:40 +03:00
package.json Bug 1393825 - Update Codemirror to 5.29.0. r=bgrins 2017-08-29 01:18:54 -04:00
README Bug 1486298 - Update CodeMirror to 5.44.0 and add ClojureScript syntax highlighting. r=bgrins 2018-08-26 22:20:53 -04:00
wasm.js Bug 1454696 - Run eslint --fix for prefer-const;r=yulia 2018-06-01 12:36:09 +02:00
webpack.config.js Backed out changeset 41d517d39bdd (bug 1466558) for devtools failures in devtools/client/sourceeditor/test/browser_vinemacs.js on a CLOSED TREE 2018-06-08 20:57:01 +03:00

This is the CodeMirror editor packaged for the Mozilla Project. CodeMirror
is a JavaScript component that provides a code editor in the browser. When
a mode is available for the language you are coding in, it will color your
code, and optionally help with indentation.

# Upgrade

Currently used version is 5.40.0. To upgrade: download a new version of
CodeMirror from the project's page [1] and replace all JavaScript and
CSS files inside the codemirror directory [2].

Then to recreate codemirror.bundle.js:
 > cd devtools/client/sourceeditor
 > npm install
 > webpack

To confirm the functionality run mochitests for the following components:

 * sourceeditor
 * scratchpad
 * debugger
 * styleditor
 * netmonitor

The sourceeditor component contains imported CodeMirror tests [3].

 * Some tests were commented out because we don't use that functionality
   within Firefox (for example Ruby editing mode). Be careful when updating
   files test/codemirror.html and test/vimemacs.html; they were modified to
   co-exist with Mozilla's testing infrastructure. Basically, vimemacs.html
   is a copy of codemirror.html but only with VIM and Emacs mode tests
   enabled.
 * In cm_comment_test.js comment out fallbackToBlock and fallbackToLine
   tests.
 * The search addon (search.js) was slightly modified to make search
   UI localizable (see patch below).

Other than that, we don't have any Mozilla-specific patches applied to
CodeMirror itself.

# Addons

To install a new CodeMirror addon add it to the codemirror directory,
jar.mn [4] file and editor.js [5]. Also, add it to the License section
below.

# License

The following files in this directory and devtools/client/sourceeditor/test/codemirror/
are licensed according to the contents in the LICENSE file.

# Localization patches

diff --git a/devtools/client/sourceeditor/codemirror/addon/search/search.js b/devtools/client/sourceeditor/codemirror/addon/search/search.js
--- a/devtools/client/sourceeditor/codemirror/addon/search/search.js
+++ b/devtools/client/sourceeditor/codemirror/addon/search/search.js
@@ -93,32 +93,47 @@
     } else {
       query = parseString(query)
     }
     if (typeof query == "string" ? query == "" : query.test(""))
       query = /x^/;
     return query;
   }

-  var queryDialog =
-    '<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>';
+  var queryDialog;

   function startSearch(cm, state, query) {
     state.queryText = query;
     state.query = parseQuery(query);
     cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
     state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
     cm.addOverlay(state.overlay);
     if (cm.showMatchesOnScrollbar) {
       if (state.annotate) { state.annotate.clear(); state.annotate = null; }
       state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
     }
   }

   function doSearch(cm, rev, persistent, immediate) {
+    if (!queryDialog) {
+      let doc = cm.getWrapperElement().ownerDocument;
+      let inp = doc.createElement("input");
+
+      inp.type = "search";
+      inp.placeholder = cm.l10n("findCmd.promptMessage");
+      inp.style.marginInlineStart = "1em";
+      inp.style.marginInlineEnd = "1em";
+      inp.style.flexGrow = "1";
+      inp.addEventListener("focus", () => inp.select());
+
+      queryDialog = doc.createElement("div");
+      queryDialog.appendChild(inp);
+      queryDialog.style.display = "flex";
+    }
+
     var state = getSearchState(cm);
     if (state.query) return findNext(cm, rev);
     var q = cm.getSelection() || state.lastQuery;
     if (q instanceof RegExp && q.source == "x^") q = null
     if (persistent && cm.openDialog) {
       var hiding = null
       var searchNext = function(query, event) {
         CodeMirror.e_stop(event);
@@ -181,56 +196,110 @@
     var state = getSearchState(cm);
     state.lastQuery = state.query;
     if (!state.query) return;
     state.query = state.queryText = null;
     cm.removeOverlay(state.overlay);
     if (state.annotate) { state.annotate.clear(); state.annotate = null; }
   });}

-  var replaceQueryDialog =
-    ' <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>';
-  var replacementQueryDialog = '<span class="CodeMirror-search-label">With:</span> <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
-  var doReplaceConfirm = '<span class="CodeMirror-search-label">Replace?</span> <button>Yes</button> <button>No</button> <button>All</button> <button>Stop</button>';
-
   function replaceAll(cm, query, text) {
     cm.operation(function() {
       for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
         if (typeof query != "string") {
           var match = cm.getRange(cursor.from(), cursor.to()).match(query);
           cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
         } else cursor.replace(text);
       }
     });
   }

   function replace(cm, all) {
     if (cm.getOption("readOnly")) return;
     var query = cm.getSelection() || getSearchState(cm).lastQuery;
-    var dialogText = '<span class="CodeMirror-search-label">' + (all ? 'Replace all:' : 'Replace:') + '</span>';
-    dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) {
+
+    let doc = cm.getWrapperElement().ownerDocument;
+
+    // `searchLabel` is used as part of `replaceQueryFragment` and as a separate
+    // argument by itself, so it should be cloned.
+    let searchLabel = doc.createElement("span");
+    searchLabel.classList.add("CodeMirror-search-label");
+    searchLabel.textContent = all ? "Replace all:" : "Replace:";
+
+    let replaceQueryFragment = doc.createDocumentFragment();
+    replaceQueryFragment.appendChild(searchLabel.cloneNode(true));
+
+    let searchField = doc.createElement("input");
+    searchField.setAttribute("type", "text");
+    searchField.setAttribute("style", "width: 10em");
+    searchField.classList.add("CodeMirror-search-field");
+    replaceQueryFragment.appendChild(searchField);
+
+    let searchHint = doc.createElement("span");
+    searchHint.setAttribute("style", "color: #888");
+    searchHint.classList.add("CodeMirror-search-hint");
+    searchHint.textContent = "(Use /re/ syntax for regexp search)";
+    replaceQueryFragment.appendChild(searchHint);
+
+    dialog(cm, replaceQueryFragment, searchLabel, query, function(query) {
       if (!query) return;
       query = parseQuery(query);
-      dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
+
+      let replacementQueryFragment = doc.createDocumentFragment();
+
+      let replaceWithLabel = searchLabel.cloneNode(false);
+      replaceWithLabel.textContent = "With:";
+      replacementQueryFragment.appendChild(replaceWithLabel);
+
+      let replaceField = doc.createElement("input");
+      replaceField.setAttribute("type", "text");
+      replaceField.setAttribute("style", "width: 10em");
+      replaceField.classList.add("CodeMirror-search-field");
+      replacementQueryFragment.appendChild(replaceField);
+
+      dialog(cm, replacementQueryFragment, "Replace with:", "", function(text) {
         text = parseString(text)
         if (all) {
           replaceAll(cm, query, text)
         } else {
           clearSearch(cm);
           var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
           var advance = function() {
             var start = cursor.from(), match;
             if (!(match = cursor.findNext())) {
               cursor = getSearchCursor(cm, query);
               if (!(match = cursor.findNext()) ||
                   (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
             }
             cm.setSelection(cursor.from(), cursor.to());
-            cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
-            confirmDialog(cm, doReplaceConfirm, "Replace?",
+            cm.scrollIntoView({ from: cursor.from(), to: cursor.to() });
+
+            let replaceConfirmFragment = doc.createDocumentFragment();
+
+            let replaceConfirmLabel = searchLabel.cloneNode(false);
+            replaceConfirmLabel.textContent = "Replace?";
+            replaceConfirmFragment.appendChild(replaceConfirmLabel);
+
+            let yesButton = doc.createElement("button");
+            yesButton.textContent = "Yes";
+            replaceConfirmFragment.appendChild(yesButton);
+
+            let noButton = doc.createElement("button");
+            noButton.textContent = "No";
+            replaceConfirmFragment.appendChild(noButton);
+
+            let allButton = doc.createElement("button");
+            allButton.textContent = "All";
+            replaceConfirmFragment.appendChild(allButton);
+
+            let stopButton = doc.createElement("button");
+            stopButton.textContent = "Stop";
+            replaceConfirmFragment.appendChild(stopButton);
+
+            confirmDialog(cm, replaceConfirmFragment, "Replace?",
                           [function() {doReplace(match);}, advance,
                            function() {replaceAll(cm, query, text)}]);
           };
           var doReplace = function(match) {
             cursor.replace(typeof query == "string" ? text :
                            text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
             advance();
           };

# Footnotes

[1] http://codemirror.net
[2] devtools/client/sourceeditor/codemirror
[3] devtools/client/sourceeditor/test/browser_codemirror.js
[4] devtools/client/jar.mn
[5] devtools/client/sourceeditor/editor.js