/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at . */ import { isWasm, getWasmLineNumberFormatter, renderWasmText } from "../wasm"; import { isMinified } from "../isMinified"; import { resizeBreakpointGutter, resizeToggleButton } from "../ui"; import { javascriptLikeExtensions } from "../source"; const sourceDocs = new Map(); export function getDocument(key) { return sourceDocs.get(key); } export function hasDocument(key) { return sourceDocs.has(key); } export function setDocument(key, doc) { sourceDocs.set(key, doc); } export function removeDocument(key) { sourceDocs.delete(key); } export function clearDocuments() { sourceDocs.clear(); } export function clearDocumentsForSources(sources) { for (const source of sources) { sourceDocs.delete(source.id); } } function resetLineNumberFormat(editor) { const cm = editor.codeMirror; cm.setOption("lineNumberFormatter", number => number); resizeBreakpointGutter(cm); resizeToggleButton(cm); } function updateLineNumberFormat(editor, sourceId) { if (!isWasm(sourceId)) { resetLineNumberFormat(editor); return; } const cm = editor.codeMirror; const lineNumberFormatter = getWasmLineNumberFormatter(sourceId); cm.setOption("lineNumberFormatter", lineNumberFormatter); resizeBreakpointGutter(cm); resizeToggleButton(cm); } export function updateDocument(editor, source) { if (!source) { return; } const sourceId = source.id; const doc = getDocument(sourceId) || editor.createDocument(); editor.replaceDocument(doc); updateLineNumberFormat(editor, sourceId); } /* used to apply the context menu wrap line option change to all the docs */ export function updateDocuments(updater) { for (const doc of sourceDocs.values()) { if (doc.cm == null) { continue; } else { updater(doc); } } } export function clearEditor(editor) { const doc = editor.createDocument("", { name: "text" }); editor.replaceDocument(doc); resetLineNumberFormat(editor); } export function showLoading(editor) { // Create the "loading message" document only once let doc = getDocument("loading"); if (!doc) { doc = editor.createDocument(L10N.getStr("loadingText"), { name: "text" }); setDocument("loading", doc); } // `createDocument` won't be used right away in the editor, we still need to // explicitely update it editor.replaceDocument(doc); } export function showErrorMessage(editor, msg) { let error; if (msg.includes("WebAssembly binary source is not available")) { error = L10N.getStr("wasmIsNotAvailable"); } else { error = L10N.getFormatStr("errorLoadingText3", msg); } const doc = editor.createDocument(error, { name: "text" }); editor.replaceDocument(doc); resetLineNumberFormat(editor); } const contentTypeModeMap = new Map([ ["text/javascript", { name: "javascript" }], ["text/typescript", { name: "javascript", typescript: true }], ["text/coffeescript", { name: "coffeescript" }], [ "text/typescript-jsx", { name: "jsx", base: { name: "javascript", typescript: true }, }, ], ["text/jsx", { name: "jsx" }], ["text/x-elm", { name: "elm" }], ["text/x-clojure", { name: "clojure" }], ["text/x-clojurescript", { name: "clojure" }], ["text/wasm", { name: "text" }], ["text/html", { name: "htmlmixed" }], ["text/plain", { name: "text" }], ]); const nonJSLanguageExtensionMap = new Map([ ["c", { name: "text/x-csrc" }], ["kt", { name: "text/x-kotlin" }], ["cpp", { name: "text/x-c++src" }], ["m", { name: "text/x-objectivec" }], ["rs", { name: "text/x-rustsrc" }], ["hx", { name: "text/x-haxe" }], ]); /** * Returns Code Mirror mode for source content type */ // eslint-disable-next-line complexity export function getMode(source, sourceTextContent, symbols) { const content = sourceTextContent.value; // Disable modes for minified files with 1+ million characters (See Bug 1569829). if ( content.type === "text" && isMinified(source, sourceTextContent) && content.value.length > 1000000 ) { return contentTypeModeMap.get("text/plain"); } if (content.type !== "text") { return contentTypeModeMap.get("text/plain"); } const extension = source.displayURL.fileExtension; if (extension === "jsx" || (symbols && symbols.hasJsx)) { if (symbols && symbols.hasTypes) { return contentTypeModeMap.get("text/typescript-jsx"); } return contentTypeModeMap.get("text/jsx"); } if (symbols && symbols.hasTypes) { if (symbols.hasJsx) { return contentTypeModeMap.get("text/typescript-jsx"); } return contentTypeModeMap.get("text/typescript"); } // check for C and other non JS languages if (nonJSLanguageExtensionMap.has(extension)) { return nonJSLanguageExtensionMap.get(extension); } // if the url ends with a known Javascript-like URL, provide JavaScript mode. if (javascriptLikeExtensions.has(extension)) { return contentTypeModeMap.get("text/javascript"); } const { contentType, value: text } = content; // Use HTML mode for files in which the first non whitespace // character is `<` regardless of extension. const isHTMLLike = () => text.match(/^\s* wasmLines, match: () => false }); } updateLineNumberFormat(editor, source.id); }