diff --git a/package-lock.json b/package-lock.json
index c141e654a..0eca777cb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,6 +6,11 @@
     "": {
       "dependencies": {
         "@codemirror/commands": "^6.0.1",
+        "@codemirror/lang-html": "^6.1.0",
+        "@codemirror/lang-javascript": "^6.0.2",
+        "@codemirror/lang-json": "^6.0.0",
+        "@codemirror/lang-markdown": "^6.0.1",
+        "@codemirror/lang-php": "^6.0.0",
         "@codemirror/language": "^6.2.1",
         "@codemirror/legacy-modes": "^6.1.0",
         "@codemirror/state": "^6.1.0",
@@ -55,6 +60,79 @@
         "@lezer/common": "^1.0.0"
       }
     },
+    "node_modules/@codemirror/lang-css": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.0.0.tgz",
+      "integrity": "sha512-jBqc+BTuwhNOTlrimFghLlSrN6iFuE44HULKWoR4qKYObhOIl9Lci1iYj6zMIte1XTQmZguNvjXMyr43LUKwSw==",
+      "dependencies": {
+        "@codemirror/autocomplete": "^6.0.0",
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/state": "^6.0.0",
+        "@lezer/css": "^1.0.0"
+      }
+    },
+    "node_modules/@codemirror/lang-html": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.1.0.tgz",
+      "integrity": "sha512-gA7NmJxqvnhwza05CvR7W/39Ap9r/4Vs9uiC0IeFYo1hSlJzc/8N6Evviz6vTW1x8SpHcRYyqKOf6rpl6LfWtg==",
+      "dependencies": {
+        "@codemirror/autocomplete": "^6.0.0",
+        "@codemirror/lang-css": "^6.0.0",
+        "@codemirror/lang-javascript": "^6.0.0",
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/state": "^6.0.0",
+        "@lezer/common": "^1.0.0",
+        "@lezer/html": "^1.0.0"
+      }
+    },
+    "node_modules/@codemirror/lang-javascript": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.0.2.tgz",
+      "integrity": "sha512-BZRJ9u/zl16hLkSpDAWm73mrfIR7HJrr0lvnhoSOCQVea5BglguWI/slxexhvUb0CB5cXgKWuo2bM+N9EhIaZw==",
+      "dependencies": {
+        "@codemirror/autocomplete": "^6.0.0",
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/lint": "^6.0.0",
+        "@codemirror/state": "^6.0.0",
+        "@codemirror/view": "^6.0.0",
+        "@lezer/common": "^1.0.0",
+        "@lezer/javascript": "^1.0.0"
+      }
+    },
+    "node_modules/@codemirror/lang-json": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.0.tgz",
+      "integrity": "sha512-DvTcYTKLmg2viADXlTdufrT334M9jowe1qO02W28nvm+nejcvhM5vot5mE8/kPrxYw/HJHhwu1z2PyBpnMLCNQ==",
+      "dependencies": {
+        "@codemirror/language": "^6.0.0",
+        "@lezer/json": "^1.0.0"
+      }
+    },
+    "node_modules/@codemirror/lang-markdown": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.0.1.tgz",
+      "integrity": "sha512-pHPQuRwf9cUrmkmsTHRjtS9ZnGu3fA9YzAdh2++d+L9wbfnC2XbKh0Xvm/0YiUjdCnoCx9wDFEoCuAnkqKWLIw==",
+      "dependencies": {
+        "@codemirror/lang-html": "^6.0.0",
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/state": "^6.0.0",
+        "@codemirror/view": "^6.0.0",
+        "@lezer/common": "^1.0.0",
+        "@lezer/markdown": "^1.0.0"
+      }
+    },
+    "node_modules/@codemirror/lang-php": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-php/-/lang-php-6.0.0.tgz",
+      "integrity": "sha512-96CEjq0xEgbzc6bdFPwILPfZ6m8917JRbh2oPszZJABlYxG4Y+eYjtYkUTDb4yuyjQKyigHoeGC6zoIOYA1NWA==",
+      "dependencies": {
+        "@codemirror/lang-html": "^6.0.0",
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/state": "^6.0.0",
+        "@lezer/common": "^1.0.0",
+        "@lezer/php": "^1.0.0"
+      }
+    },
     "node_modules/@codemirror/language": {
       "version": "6.2.1",
       "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.2.1.tgz",
@@ -116,6 +194,15 @@
       "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.0.tgz",
       "integrity": "sha512-ohydQe+Hb+w4oMDvXzs8uuJd2NoA3D8YDcLiuDsLqH+yflDTPEpgCsWI3/6rH5C3BAedtH1/R51dxENldQceEA=="
     },
+    "node_modules/@lezer/css": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.0.0.tgz",
+      "integrity": "sha512-616VqgDKumHmYIuxs3tnX1irEQmoDHgF/TlP4O5ICWwyHwLMErq+8iKVuzTkOdBqvYAVmObqThcDEAaaMJjAdg==",
+      "dependencies": {
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.0.0"
+      }
+    },
     "node_modules/@lezer/highlight": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.0.0.tgz",
@@ -124,6 +211,34 @@
         "@lezer/common": "^1.0.0"
       }
     },
+    "node_modules/@lezer/html": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.0.1.tgz",
+      "integrity": "sha512-sC00zEt3GBh3vVO6QaGX4YZCl41S9dHWN/WGBsDixy9G+sqOC7gsa4cxA/fmRVAiBvhqYkJk+5Ul4oul92CPVw==",
+      "dependencies": {
+        "@lezer/common": "^1.0.0",
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.0.0"
+      }
+    },
+    "node_modules/@lezer/javascript": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.0.2.tgz",
+      "integrity": "sha512-IjOVeIRhM8IuafWNnk+UzRz7p4/JSOKBNINLYLsdSGuJS9Ju7vFdc82AlTt0jgtV5D8eBZf4g0vK4d3ttBNz7A==",
+      "dependencies": {
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.0.0"
+      }
+    },
+    "node_modules/@lezer/json": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.0.tgz",
+      "integrity": "sha512-zbAuUY09RBzCoCA3lJ1+ypKw5WSNvLqGMtasdW6HvVOqZoCpPr8eWrsGnOVWGKGn8Rh21FnrKRVlJXrGAVUqRw==",
+      "dependencies": {
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.0.0"
+      }
+    },
     "node_modules/@lezer/lr": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.0.tgz",
@@ -132,6 +247,24 @@
         "@lezer/common": "^1.0.0"
       }
     },
+    "node_modules/@lezer/markdown": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.0.1.tgz",
+      "integrity": "sha512-LlpNWLqes3XQvd8TwpJTHf9ENl4fI6H32xQkMgltUITFMMdQpOASXQtDawWR03yS6hskh4bkhATQbgjdGMoUvA==",
+      "dependencies": {
+        "@lezer/common": "^1.0.0",
+        "@lezer/highlight": "^1.0.0"
+      }
+    },
+    "node_modules/@lezer/php": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@lezer/php/-/php-1.0.0.tgz",
+      "integrity": "sha512-kFQu/mk/vmjpA+fjQU87d9eimqKJ9PFCa8CZCPFWGEwNnm7Ahpw32N+HYEU/YAQ0XcfmOAnW/YJCEa8WpUOMMw==",
+      "dependencies": {
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.0.0"
+      }
+    },
     "node_modules/ansi-regex": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
@@ -2053,6 +2186,79 @@
         "@lezer/common": "^1.0.0"
       }
     },
+    "@codemirror/lang-css": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.0.0.tgz",
+      "integrity": "sha512-jBqc+BTuwhNOTlrimFghLlSrN6iFuE44HULKWoR4qKYObhOIl9Lci1iYj6zMIte1XTQmZguNvjXMyr43LUKwSw==",
+      "requires": {
+        "@codemirror/autocomplete": "^6.0.0",
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/state": "^6.0.0",
+        "@lezer/css": "^1.0.0"
+      }
+    },
+    "@codemirror/lang-html": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.1.0.tgz",
+      "integrity": "sha512-gA7NmJxqvnhwza05CvR7W/39Ap9r/4Vs9uiC0IeFYo1hSlJzc/8N6Evviz6vTW1x8SpHcRYyqKOf6rpl6LfWtg==",
+      "requires": {
+        "@codemirror/autocomplete": "^6.0.0",
+        "@codemirror/lang-css": "^6.0.0",
+        "@codemirror/lang-javascript": "^6.0.0",
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/state": "^6.0.0",
+        "@lezer/common": "^1.0.0",
+        "@lezer/html": "^1.0.0"
+      }
+    },
+    "@codemirror/lang-javascript": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.0.2.tgz",
+      "integrity": "sha512-BZRJ9u/zl16hLkSpDAWm73mrfIR7HJrr0lvnhoSOCQVea5BglguWI/slxexhvUb0CB5cXgKWuo2bM+N9EhIaZw==",
+      "requires": {
+        "@codemirror/autocomplete": "^6.0.0",
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/lint": "^6.0.0",
+        "@codemirror/state": "^6.0.0",
+        "@codemirror/view": "^6.0.0",
+        "@lezer/common": "^1.0.0",
+        "@lezer/javascript": "^1.0.0"
+      }
+    },
+    "@codemirror/lang-json": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.0.tgz",
+      "integrity": "sha512-DvTcYTKLmg2viADXlTdufrT334M9jowe1qO02W28nvm+nejcvhM5vot5mE8/kPrxYw/HJHhwu1z2PyBpnMLCNQ==",
+      "requires": {
+        "@codemirror/language": "^6.0.0",
+        "@lezer/json": "^1.0.0"
+      }
+    },
+    "@codemirror/lang-markdown": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.0.1.tgz",
+      "integrity": "sha512-pHPQuRwf9cUrmkmsTHRjtS9ZnGu3fA9YzAdh2++d+L9wbfnC2XbKh0Xvm/0YiUjdCnoCx9wDFEoCuAnkqKWLIw==",
+      "requires": {
+        "@codemirror/lang-html": "^6.0.0",
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/state": "^6.0.0",
+        "@codemirror/view": "^6.0.0",
+        "@lezer/common": "^1.0.0",
+        "@lezer/markdown": "^1.0.0"
+      }
+    },
+    "@codemirror/lang-php": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/@codemirror/lang-php/-/lang-php-6.0.0.tgz",
+      "integrity": "sha512-96CEjq0xEgbzc6bdFPwILPfZ6m8917JRbh2oPszZJABlYxG4Y+eYjtYkUTDb4yuyjQKyigHoeGC6zoIOYA1NWA==",
+      "requires": {
+        "@codemirror/lang-html": "^6.0.0",
+        "@codemirror/language": "^6.0.0",
+        "@codemirror/state": "^6.0.0",
+        "@lezer/common": "^1.0.0",
+        "@lezer/php": "^1.0.0"
+      }
+    },
     "@codemirror/language": {
       "version": "6.2.1",
       "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.2.1.tgz",
@@ -2114,6 +2320,15 @@
       "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.0.tgz",
       "integrity": "sha512-ohydQe+Hb+w4oMDvXzs8uuJd2NoA3D8YDcLiuDsLqH+yflDTPEpgCsWI3/6rH5C3BAedtH1/R51dxENldQceEA=="
     },
+    "@lezer/css": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.0.0.tgz",
+      "integrity": "sha512-616VqgDKumHmYIuxs3tnX1irEQmoDHgF/TlP4O5ICWwyHwLMErq+8iKVuzTkOdBqvYAVmObqThcDEAaaMJjAdg==",
+      "requires": {
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.0.0"
+      }
+    },
     "@lezer/highlight": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.0.0.tgz",
@@ -2122,6 +2337,34 @@
         "@lezer/common": "^1.0.0"
       }
     },
+    "@lezer/html": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.0.1.tgz",
+      "integrity": "sha512-sC00zEt3GBh3vVO6QaGX4YZCl41S9dHWN/WGBsDixy9G+sqOC7gsa4cxA/fmRVAiBvhqYkJk+5Ul4oul92CPVw==",
+      "requires": {
+        "@lezer/common": "^1.0.0",
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.0.0"
+      }
+    },
+    "@lezer/javascript": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.0.2.tgz",
+      "integrity": "sha512-IjOVeIRhM8IuafWNnk+UzRz7p4/JSOKBNINLYLsdSGuJS9Ju7vFdc82AlTt0jgtV5D8eBZf4g0vK4d3ttBNz7A==",
+      "requires": {
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.0.0"
+      }
+    },
+    "@lezer/json": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.0.tgz",
+      "integrity": "sha512-zbAuUY09RBzCoCA3lJ1+ypKw5WSNvLqGMtasdW6HvVOqZoCpPr8eWrsGnOVWGKGn8Rh21FnrKRVlJXrGAVUqRw==",
+      "requires": {
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.0.0"
+      }
+    },
     "@lezer/lr": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.0.tgz",
@@ -2130,6 +2373,24 @@
         "@lezer/common": "^1.0.0"
       }
     },
+    "@lezer/markdown": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.0.1.tgz",
+      "integrity": "sha512-LlpNWLqes3XQvd8TwpJTHf9ENl4fI6H32xQkMgltUITFMMdQpOASXQtDawWR03yS6hskh4bkhATQbgjdGMoUvA==",
+      "requires": {
+        "@lezer/common": "^1.0.0",
+        "@lezer/highlight": "^1.0.0"
+      }
+    },
+    "@lezer/php": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@lezer/php/-/php-1.0.0.tgz",
+      "integrity": "sha512-kFQu/mk/vmjpA+fjQU87d9eimqKJ9PFCa8CZCPFWGEwNnm7Ahpw32N+HYEU/YAQ0XcfmOAnW/YJCEa8WpUOMMw==",
+      "requires": {
+        "@lezer/highlight": "^1.0.0",
+        "@lezer/lr": "^1.0.0"
+      }
+    },
     "ansi-regex": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
diff --git a/package.json b/package.json
index 8407ffc77..4d2b70247 100644
--- a/package.json
+++ b/package.json
@@ -24,6 +24,11 @@
   },
   "dependencies": {
     "@codemirror/commands": "^6.0.1",
+    "@codemirror/lang-html": "^6.1.0",
+    "@codemirror/lang-javascript": "^6.0.2",
+    "@codemirror/lang-json": "^6.0.0",
+    "@codemirror/lang-markdown": "^6.0.1",
+    "@codemirror/lang-php": "^6.0.0",
     "@codemirror/language": "^6.2.1",
     "@codemirror/legacy-modes": "^6.1.0",
     "@codemirror/state": "^6.1.0",
diff --git a/resources/js/code/index.mjs b/resources/js/code/index.mjs
index ff60cbff5..6ef659994 100644
--- a/resources/js/code/index.mjs
+++ b/resources/js/code/index.mjs
@@ -1,10 +1,9 @@
 import {EditorView} from "@codemirror/view"
-// import {EditorState} from "@codemirror/state"
 import Clipboard from "clipboard/dist/clipboard.min";
 
 // Modes
-import {modes, modeMap, modesAsStreamLanguages} from "./modes";
 import {viewer} from "./setups.js";
+import {createView, updateViewLanguage} from "./views.js";
 
 /**
  * Highlight pre elements on a page
@@ -36,26 +35,24 @@ function highlightElem(elem) {
     elem.innerHTML = elem.innerHTML.replace(/<br\s*[\/]?>/gi ,'\n');
     const content = elem.textContent.trimEnd();
 
-    let mode = '';
+    let langName = '';
     if (innerCodeElem !== null) {
-        const langName = innerCodeElem.className.replace('language-', '');
-        mode = getMode(langName, content);
+        langName = innerCodeElem.className.replace('language-', '');
     }
 
     const wrapper = document.createElement('div');
     elem.parentNode.insertBefore(wrapper, elem);
 
-    const cm = new EditorView({
+    const ev = createView({
         parent: wrapper,
         doc: content,
         extensions: viewer(),
     });
+    setMode(ev, langName, content);
 
     elem.remove();
 
-    // TODO - theme: getTheme(),
-    // TODO - mode,
-    addCopyIcon(cm);
+    addCopyIcon(ev);
 }
 
 /**
@@ -84,28 +81,6 @@ function addCopyIcon(cmInstance) {
     // });
 }
 
-/**
- * Search for a codemirror code based off a user suggestion
- * @param {String} suggestion
- * @param {String} content
- * @returns {string}
- */
-function getMode(suggestion, content) {
-    suggestion = suggestion.trim().replace(/^\./g, '').toLowerCase();
-
-    const modeMapType = typeof modeMap[suggestion];
-
-    if (modeMapType === 'undefined') {
-        return '';
-    }
-
-    if (modeMapType === 'function') {
-        return modeMap[suggestion](content);
-    }
-
-    return modeMap[suggestion];
-}
-
 /**
  * Ge the theme to use for CodeMirror instances.
  * @returns {*|string}
@@ -172,12 +147,14 @@ export function inlineEditor(textArea, mode) {
 }
 
 /**
- * Set the mode of a codemirror instance.
- * @param cmInstance
- * @param modeSuggestion
+ * Set the language mode of a codemirror EditorView.
+ *
+ * @param {EditorView} ev
+ * @param {string} modeSuggestion
+ * @param {string} content
  */
-export function setMode(cmInstance, modeSuggestion, content) {
-      cmInstance.setOption('mode', getMode(modeSuggestion, content));
+export function setMode(ev, modeSuggestion, content) {
+    updateViewLanguage(ev, modeSuggestion, content);
 }
 
 /**
diff --git a/resources/js/code/languages.js b/resources/js/code/languages.js
new file mode 100644
index 000000000..4b04bdb14
--- /dev/null
+++ b/resources/js/code/languages.js
@@ -0,0 +1,120 @@
+import {StreamLanguage} from "@codemirror/language"
+
+import {css} from '@codemirror/legacy-modes/mode/css';
+import {c, java, cpp, csharp, kotlin, scala} from '@codemirror/legacy-modes/mode/clike';
+import {diff} from '@codemirror/legacy-modes/mode/diff';
+import {fortran} from '@codemirror/legacy-modes/mode/fortran';
+import {go} from '@codemirror/legacy-modes/mode/go';
+import {haskell} from '@codemirror/legacy-modes/mode/haskell';
+import {html} from '@codemirror/lang-html';
+import {javascript} from '@codemirror/lang-javascript';
+import {json} from '@codemirror/lang-json';
+import {julia} from '@codemirror/legacy-modes/mode/julia';
+import {lua} from '@codemirror/legacy-modes/mode/lua';
+import {markdown} from '@codemirror/lang-markdown';
+import {oCaml, fSharp, sml} from '@codemirror/legacy-modes/mode/mllike';
+import {nginx} from '@codemirror/legacy-modes/mode/nginx';
+import {perl} from '@codemirror/legacy-modes/mode/perl';
+import {pascal} from '@codemirror/legacy-modes/mode/pascal';
+import {php} from '@codemirror/lang-php';
+import {powerShell} from '@codemirror/legacy-modes/mode/powershell';
+import {properties} from '@codemirror/legacy-modes/mode/properties';
+import {python} from '@codemirror/legacy-modes/mode/python';
+import {ruby} from '@codemirror/legacy-modes/mode/ruby';
+import {rust} from '@codemirror/legacy-modes/mode/rust';
+import {shell} from '@codemirror/legacy-modes/mode/shell';
+import {sql} from '@codemirror/legacy-modes/mode/sql';
+import {stex} from '@codemirror/legacy-modes/mode/stex';
+import {toml} from '@codemirror/legacy-modes/mode/toml';
+import {vb} from '@codemirror/legacy-modes/mode/vb';
+import {vbScript} from '@codemirror/legacy-modes/mode/vbscript';
+import {xml} from '@codemirror/legacy-modes/mode/xml';
+import {yaml} from '@codemirror/legacy-modes/mode/yaml';
+
+
+// Mapping of possible languages or formats from user input to their codemirror modes.
+// Value can be a mode string or a function that will receive the code content & return the mode string.
+// The function option is used in the event the exact mode could be dynamic depending on the code.
+const modeMap = {
+    bash: () => StreamLanguage.define(shell),
+    css: () => StreamLanguage.define(css),
+    c: () => StreamLanguage.define(c),
+    java: () => StreamLanguage.define(java),
+    scala: () => StreamLanguage.define(scala),
+    kotlin: () => StreamLanguage.define(kotlin),
+    'c++': () => StreamLanguage.define(cpp),
+    'c#': () => StreamLanguage.define(csharp),
+    csharp: () => StreamLanguage.define(csharp),
+    diff: () => StreamLanguage.define(diff),
+    for: () => StreamLanguage.define(fortran),
+    fortran: () => StreamLanguage.define(fortran),
+    'f#': () => StreamLanguage.define(fSharp),
+    fsharp: () => StreamLanguage.define(fSharp),
+    go: () => StreamLanguage.define(go),
+    haskell: () => StreamLanguage.define(haskell),
+    hs: () => StreamLanguage.define(haskell),
+    html: () => html(),
+    ini: () => StreamLanguage.define(properties),
+    javascript: () => javascript(),
+    json: () => json(),
+    js: () => javascript(),
+    jl: () => StreamLanguage.define(julia),
+    julia: () => StreamLanguage.define(julia),
+    latex: () => StreamLanguage.define(stex),
+    lua: () => StreamLanguage.define(lua),
+    md: () => StreamLanguage.define(markdown),
+    mdown: () => StreamLanguage.define(markdown),
+    markdown: () => StreamLanguage.define(markdown),
+    ml: () => StreamLanguage.define(sml),
+    nginx: () => StreamLanguage.define(nginx),
+    perl: () => StreamLanguage.define(perl),
+    pl: () => StreamLanguage.define(perl),
+    powershell: () => StreamLanguage.define(powerShell),
+    properties: () => StreamLanguage.define(properties),
+    ocaml: () => StreamLanguage.define(oCaml),
+    pascal: () => StreamLanguage.define(pascal),
+    pas: () => StreamLanguage.define(pascal),
+    php: (code) => {
+        const hasTags = code.includes('<?php');
+        return php({plain: !hasTags});
+    },
+    py: () => StreamLanguage.define(python),
+    python: () => StreamLanguage.define(python),
+    ruby: () => StreamLanguage.define(ruby),
+    rust: () => StreamLanguage.define(rust),
+    rb: () => StreamLanguage.define(ruby),
+    rs: () => StreamLanguage.define(rust),
+    shell: () => StreamLanguage.define(shell),
+    sh: () => StreamLanguage.define(shell),
+    stext: () => StreamLanguage.define(stex),
+    toml: () => StreamLanguage.define(toml),
+    ts: () => javascript({typescript: true}),
+    typescript: () => javascript({typescript: true}),
+    sql: () => StreamLanguage.define(sql),
+    vbs: () => StreamLanguage.define(vbScript),
+    vbscript: () => StreamLanguage.define(vbScript),
+    'vb.net': () => StreamLanguage.define(vb),
+    vbnet: () => StreamLanguage.define(vb),
+    xml: () => StreamLanguage.define(xml),
+    yaml: () => StreamLanguage.define(yaml),
+    yml: () => StreamLanguage.define(yaml),
+};
+
+/**
+ * Get the relevant codemirror language extension based upon the given language
+ * suggestion and content.
+ * @param {String} langSuggestion
+ * @param {String} content
+ * @returns {StreamLanguage}
+ */
+export function getLanguageExtension(langSuggestion, content) {
+    const suggestion = langSuggestion.trim().replace(/^\./g, '').toLowerCase();
+
+    const language = modeMap[suggestion];
+
+    if (typeof language === 'undefined') {
+        return undefined;
+    }
+
+    return language(content);
+}
\ No newline at end of file
diff --git a/resources/js/code/modes.js b/resources/js/code/modes.js
deleted file mode 100644
index 5a89255a5..000000000
--- a/resources/js/code/modes.js
+++ /dev/null
@@ -1,134 +0,0 @@
-import {StreamLanguage} from "@codemirror/language"
-
-import {css as langCss} from '@codemirror/legacy-modes/mode/css';
-import {clike as langClike} from '@codemirror/legacy-modes/mode/clike';
-import {diff as langDiff} from '@codemirror/legacy-modes/mode/diff';
-import {fortran as langFortran} from '@codemirror/legacy-modes/mode/fortran';
-import {go as langGo} from '@codemirror/legacy-modes/mode/go';
-import {haskell as langHaskell} from '@codemirror/legacy-modes/mode/haskell';
-// import {htmlmixed as langHtmlmixed} from '@codemirror/legacy-modes/mode/htmlmixed';
-import {javascript as langJavascript} from '@codemirror/legacy-modes/mode/javascript';
-import {julia as langJulia} from '@codemirror/legacy-modes/mode/julia';
-import {lua as langLua} from '@codemirror/legacy-modes/mode/lua';
-// import {markdown as langMarkdown} from '@codemirror/legacy-modes/mode/markdown';
-import {oCaml as langMllike} from '@codemirror/legacy-modes/mode/mllike';
-import {nginx as langNginx} from '@codemirror/legacy-modes/mode/nginx';
-import {perl as langPerl} from '@codemirror/legacy-modes/mode/perl';
-import {pascal as langPascal} from '@codemirror/legacy-modes/mode/pascal';
-// import {php as langPhp} from '@codemirror/legacy-modes/mode/php';
-import {powerShell as langPowershell} from '@codemirror/legacy-modes/mode/powershell';
-import {properties as langProperties} from '@codemirror/legacy-modes/mode/properties';
-import {python as langPython} from '@codemirror/legacy-modes/mode/python';
-import {ruby as langRuby} from '@codemirror/legacy-modes/mode/ruby';
-import {rust as langRust} from '@codemirror/legacy-modes/mode/rust';
-import {shell as langShell} from '@codemirror/legacy-modes/mode/shell';
-import {sql as langSql} from '@codemirror/legacy-modes/mode/sql';
-import {stex as langStex} from '@codemirror/legacy-modes/mode/stex';
-import {toml as langToml} from '@codemirror/legacy-modes/mode/toml';
-import {vb as langVb} from '@codemirror/legacy-modes/mode/vb';
-import {vbScript as langVbscript} from '@codemirror/legacy-modes/mode/vbscript';
-import {xml as langXml} from '@codemirror/legacy-modes/mode/xml';
-import {yaml as langYaml} from '@codemirror/legacy-modes/mode/yaml';
-
-export const modes = [
-    langCss,
-    langClike,
-    langDiff,
-    langFortran,
-    langGo,
-    langHaskell,
-    // langHtmlmixed,
-    langJavascript,
-    langJulia,
-    langLua,
-    // langMarkdown,
-    langMllike,
-    langNginx,
-    langPerl,
-    langPascal,
-    // langPhp,
-    langPowershell,
-    langProperties,
-    langPython,
-    langRuby,
-    langRust,
-    langShell,
-    langSql,
-    langStex,
-    langToml,
-    langVb,
-    langVbscript,
-    langXml,
-    langYaml,
-];
-
-// Mapping of possible languages or formats from user input to their codemirror modes.
-// Value can be a mode string or a function that will receive the code content & return the mode string.
-// The function option is used in the event the exact mode could be dynamic depending on the code.
-export const modeMap = {
-    bash: 'shell',
-    css: 'css',
-    c: 'text/x-csrc',
-    java: 'text/x-java',
-    scala: 'text/x-scala',
-    kotlin: 'text/x-kotlin',
-    'c++': 'text/x-c++src',
-    'c#': 'text/x-csharp',
-    csharp: 'text/x-csharp',
-    diff: 'diff',
-    for: 'fortran',
-    fortran: 'fortran',
-    'f#': 'text/x-fsharp',
-    fsharp: 'text/x-fsharp',
-    go: 'go',
-    haskell: 'haskell',
-    hs: 'haskell',
-    html: 'htmlmixed',
-    ini: 'properties',
-    javascript: 'text/javascript',
-    json: 'application/json',
-    js: 'text/javascript',
-    jl: 'text/x-julia',
-    julia: 'text/x-julia',
-    latex: 'text/x-stex',
-    lua: 'lua',
-    md: 'markdown',
-    mdown: 'markdown',
-    markdown: 'markdown',
-    ml: 'mllike',
-    nginx: 'nginx',
-    perl: 'perl',
-    pl: 'perl',
-    powershell: 'powershell',
-    properties: 'properties',
-    ocaml: 'text/x-ocaml',
-    pascal: 'text/x-pascal',
-    pas: 'text/x-pascal',
-    php: (content) => {
-        return content.includes('<?php') ? 'php' : 'text/x-php';
-    },
-    py: 'python',
-    python: 'python',
-    ruby: 'ruby',
-    rust: 'rust',
-    rb: 'ruby',
-    rs: 'rust',
-    shell: 'shell',
-    sh: 'shell',
-    stext: 'text/x-stex',
-    toml: 'toml',
-    ts: 'text/typescript',
-    typescript: 'text/typescript',
-    sql: 'text/x-sql',
-    vbs: 'vbscript',
-    vbscript: 'vbscript',
-    'vb.net': 'text/x-vb',
-    vbnet: 'text/x-vb',
-    xml: 'xml',
-    yaml: 'yaml',
-    yml: 'yaml',
-};
-
-export function modesAsStreamLanguages() {
-    return modes.map(mode => StreamLanguage.define(mode));
-}
\ No newline at end of file
diff --git a/resources/js/code/setups.js b/resources/js/code/setups.js
index 768d3a35d..45cc9c317 100644
--- a/resources/js/code/setups.js
+++ b/resources/js/code/setups.js
@@ -6,9 +6,6 @@ import {defaultHighlightStyle, syntaxHighlighting, bracketMatching,
 import {defaultKeymap, history, historyKeymap} from "@codemirror/commands"
 import {EditorState} from "@codemirror/state"
 
-import {modesAsStreamLanguages} from "./modes";
-
-
 export function viewer() {
     return [
         lineNumbers(),
@@ -27,6 +24,5 @@ export function viewer() {
             ...foldKeymap,
         ]),
         EditorState.readOnly.of(true),
-        ...modesAsStreamLanguages(),
     ];
 }
\ No newline at end of file
diff --git a/resources/js/code/views.js b/resources/js/code/views.js
new file mode 100644
index 000000000..e87718939
--- /dev/null
+++ b/resources/js/code/views.js
@@ -0,0 +1,38 @@
+import {getLanguageExtension} from "./languages";
+import {Compartment} from "@codemirror/state"
+import {EditorView} from "@codemirror/view"
+
+const viewLangCompartments = new WeakMap();
+
+/**
+ * Create a new editor view.
+ *
+ * @param {Object} config
+ * @returns {EditorView}
+ */
+export function createView(config) {
+    const langCompartment = new Compartment();
+    config.extensions.push(langCompartment.of([]));
+
+    const ev = new EditorView(config);
+
+    viewLangCompartments.set(ev, langCompartment);
+
+    return ev;
+}
+
+/**
+ * Set the language mode of an EditorView.
+ *
+ * @param {EditorView} ev
+ * @param {string} modeSuggestion
+ * @param {string} content
+ */
+export function updateViewLanguage(ev, modeSuggestion, content) {
+    const compartment = viewLangCompartments.get(ev);
+    const language = getLanguageExtension(modeSuggestion, content);
+
+    ev.dispatch({
+        effects: compartment.reconfigure(language ? language : [])
+    })
+}
\ No newline at end of file