Merge pull request #72 from Heavrnl/feature/codemirror

Feature/codemirror
This commit is contained in:
Baobhan Sith
2025-06-04 18:21:54 +08:00
committed by GitHub
9 changed files with 901 additions and 59 deletions
+484
View File
@@ -103,6 +103,255 @@
"node": ">=6.9.0"
}
},
"node_modules/@codemirror/autocomplete": {
"version": "6.18.6",
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz",
"integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==",
"license": "MIT",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.17.0",
"@lezer/common": "^1.0.0"
}
},
"node_modules/@codemirror/lang-cpp": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@codemirror/lang-cpp/-/lang-cpp-6.0.2.tgz",
"integrity": "sha512-6oYEYUKHvrnacXxWxYa6t4puTlbN3dgV662BDfSH8+MfjQjVmP697/KYTDOqpxgerkvoNm7q5wlFMBeX8ZMocg==",
"license": "MIT",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@lezer/cpp": "^1.0.0"
}
},
"node_modules/@codemirror/lang-css": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz",
"integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@lezer/common": "^1.0.2",
"@lezer/css": "^1.1.7"
}
},
"node_modules/@codemirror/lang-go": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-go/-/lang-go-6.0.1.tgz",
"integrity": "sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.6.0",
"@codemirror/state": "^6.0.0",
"@lezer/common": "^1.0.0",
"@lezer/go": "^1.0.0"
}
},
"node_modules/@codemirror/lang-html": {
"version": "6.4.9",
"resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz",
"integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/lang-css": "^6.0.0",
"@codemirror/lang-javascript": "^6.0.0",
"@codemirror/language": "^6.4.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.17.0",
"@lezer/common": "^1.0.0",
"@lezer/css": "^1.1.0",
"@lezer/html": "^1.3.0"
}
},
"node_modules/@codemirror/lang-java": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-java/-/lang-java-6.0.1.tgz",
"integrity": "sha512-OOnmhH67h97jHzCuFaIEspbmsT98fNdhVhmA3zCxW0cn7l8rChDhZtwiwJ/JOKXgfm4J+ELxQihxaI7bj7mJRg==",
"license": "MIT",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@lezer/java": "^1.0.0"
}
},
"node_modules/@codemirror/lang-javascript": {
"version": "6.2.4",
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz",
"integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.6.0",
"@codemirror/lint": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.17.0",
"@lezer/common": "^1.0.0",
"@lezer/javascript": "^1.0.0"
}
},
"node_modules/@codemirror/lang-json": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz",
"integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==",
"license": "MIT",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@lezer/json": "^1.0.0"
}
},
"node_modules/@codemirror/lang-markdown": {
"version": "6.3.2",
"resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.3.2.tgz",
"integrity": "sha512-c/5MYinGbFxYl4itE9q/rgN/sMTjOr8XL5OWnC+EaRMLfCbVUmmubTJfdgpfcSS2SCaT7b+Q+xi3l6CgoE+BsA==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.7.1",
"@codemirror/lang-html": "^6.0.0",
"@codemirror/language": "^6.3.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"@lezer/common": "^1.2.1",
"@lezer/markdown": "^1.0.0"
}
},
"node_modules/@codemirror/lang-php": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-php/-/lang-php-6.0.1.tgz",
"integrity": "sha512-ublojMdw/PNWa7qdN5TMsjmqkNuTBD3k6ndZ4Z0S25SBAiweFGyY68AS3xNcIOlb6DDFDvKlinLQ40vSLqf8xA==",
"license": "MIT",
"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/lang-python": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.2.1.tgz",
"integrity": "sha512-IRjC8RUBhn9mGR9ywecNhB51yePWCGgvHfY1lWN/Mrp3cKuHr0isDKia+9HnvhiWNnMpbGhWrkhuWOc09exRyw==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.3.2",
"@codemirror/language": "^6.8.0",
"@codemirror/state": "^6.0.0",
"@lezer/common": "^1.2.1",
"@lezer/python": "^1.1.4"
}
},
"node_modules/@codemirror/lang-rust": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@codemirror/lang-rust/-/lang-rust-6.0.1.tgz",
"integrity": "sha512-344EMWFBzWArHWdZn/NcgkwMvZIWUR1GEBdwG8FEp++6o6vT6KL9V7vGs2ONsKxxFUPXKI0SPcWhyYyl2zPYxQ==",
"license": "MIT",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@lezer/rust": "^1.0.0"
}
},
"node_modules/@codemirror/lang-sql": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/@codemirror/lang-sql/-/lang-sql-6.9.0.tgz",
"integrity": "sha512-xmtpWqKSgum1B1J3Ro6rf7nuPqf2+kJQg5SjrofCAcyCThOe0ihSktSoXfXuhQBnwx1QbmreBbLJM5Jru6zitg==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@codemirror/lang-xml": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.1.0.tgz",
"integrity": "sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.4.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0",
"@lezer/common": "^1.0.0",
"@lezer/xml": "^1.0.0"
}
},
"node_modules/@codemirror/lang-yaml": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/@codemirror/lang-yaml/-/lang-yaml-6.1.2.tgz",
"integrity": "sha512-dxrfG8w5Ce/QbT7YID7mWZFKhdhsaTNOYjOkSIMt1qmC4VQnXSDSYVHHHn8k6kJUfIhtLo8t1JJgltlxWdsITw==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.2.0",
"@lezer/lr": "^1.0.0",
"@lezer/yaml": "^1.0.0"
}
},
"node_modules/@codemirror/language": {
"version": "6.11.1",
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.1.tgz",
"integrity": "sha512-5kS1U7emOGV84vxC+ruBty5sUgcD0te6dyupyRVG2zaSjhTDM73LhVKUtVwiqSe6QwmEoA4SCiU8AKPFyumAWQ==",
"license": "MIT",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.23.0",
"@lezer/common": "^1.1.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0",
"style-mod": "^4.0.0"
}
},
"node_modules/@codemirror/legacy-modes": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@codemirror/legacy-modes/-/legacy-modes-6.5.1.tgz",
"integrity": "sha512-DJYQQ00N1/KdESpZV7jg9hafof/iBNp9h7TYo1SLMk86TWl9uDsVdho2dzd81K+v4retmK6mdC7WpuOQDytQqw==",
"license": "MIT",
"dependencies": {
"@codemirror/language": "^6.0.0"
}
},
"node_modules/@codemirror/lint": {
"version": "6.8.5",
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.5.tgz",
"integrity": "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==",
"license": "MIT",
"dependencies": {
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.35.0",
"crelt": "^1.0.5"
}
},
"node_modules/@codemirror/state": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz",
"integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==",
"license": "MIT",
"dependencies": {
"@marijn/find-cluster-break": "^1.0.0"
}
},
"node_modules/@codemirror/view": {
"version": "6.37.1",
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.37.1.tgz",
"integrity": "sha512-Qy4CAUwngy/VQkEz0XzMKVRcckQuqLYWKqVpDDDghBe5FSXSqfVrJn49nw3ePZHxRUz4nRmb05Lgi+9csWo4eg==",
"license": "MIT",
"dependencies": {
"@codemirror/state": "^6.5.0",
"crelt": "^1.0.6",
"style-mod": "^4.1.0",
"w3c-keyname": "^2.2.4"
}
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
@@ -797,6 +1046,172 @@
"integrity": "sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==",
"license": "MIT"
},
"node_modules/@lezer/common": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==",
"license": "MIT"
},
"node_modules/@lezer/cpp": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@lezer/cpp/-/cpp-1.1.3.tgz",
"integrity": "sha512-ykYvuFQKGsRi6IcE+/hCSGUhb/I4WPjd3ELhEblm2wS2cOznDFzO+ubK2c+ioysOnlZ3EduV+MVQFCPzAIoY3w==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/css": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.2.1.tgz",
"integrity": "sha512-2F5tOqzKEKbCUNraIXc0f6HKeyKlmMWJnBB0i4XW6dJgssrZO/YlZ2pY5xgyqDleqqhiNJ3dQhbrV2aClZQMvg==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.3.0"
}
},
"node_modules/@lezer/go": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@lezer/go/-/go-1.0.1.tgz",
"integrity": "sha512-xToRsYxwsgJNHTgNdStpcvmbVuKxTapV0dM0wey1geMMRc9aggoVyKgzYp41D2/vVOx+Ii4hmE206kvxIXBVXQ==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.3.0"
}
},
"node_modules/@lezer/highlight": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz",
"integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.0.0"
}
},
"node_modules/@lezer/html": {
"version": "1.3.10",
"resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.10.tgz",
"integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/java": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@lezer/java/-/java-1.1.3.tgz",
"integrity": "sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/javascript": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.1.tgz",
"integrity": "sha512-ATOImjeVJuvgm3JQ/bpo2Tmv55HSScE2MTPnKRMRIPx2cLhHGyX2VnqpHhtIV1tVzIjZDbcWQm+NCTF40ggZVw==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.1.3",
"@lezer/lr": "^1.3.0"
}
},
"node_modules/@lezer/json": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
"integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/lr": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
"integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.0.0"
}
},
"node_modules/@lezer/markdown": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.4.3.tgz",
"integrity": "sha512-kfw+2uMrQ/wy/+ONfrH83OkdFNM0ye5Xq96cLlaCy7h5UT9FO54DU4oRoIc0CSBh5NWmWuiIJA7NGLMJbQ+Oxg==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.0.0",
"@lezer/highlight": "^1.0.0"
}
},
"node_modules/@lezer/php": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@lezer/php/-/php-1.0.2.tgz",
"integrity": "sha512-GN7BnqtGRpFyeoKSEqxvGvhJQiI4zkgmYnDk/JIyc7H7Ifc1tkPnUn/R2R8meH3h/aBf5rzjvU8ZQoyiNDtDrA==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.1.0"
}
},
"node_modules/@lezer/python": {
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.18.tgz",
"integrity": "sha512-31FiUrU7z9+d/ElGQLJFXl+dKOdx0jALlP3KEOsGTex8mvj+SoE1FgItcHWK/axkxCHGUSpqIHt6JAWfWu9Rhg==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/rust": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@lezer/rust/-/rust-1.0.2.tgz",
"integrity": "sha512-Lz5sIPBdF2FUXcWeCu1//ojFAZqzTQNRga0aYv6dYXqJqPfMdCAI0NzajWUd4Xijj1IKJLtjoXRPMvTKWBcqKg==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/xml": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.6.tgz",
"integrity": "sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0"
}
},
"node_modules/@lezer/yaml": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@lezer/yaml/-/yaml-1.0.3.tgz",
"integrity": "sha512-GuBLekbw9jDBDhGur82nuwkxKQ+a3W5H0GfaAthDXcAu+XdpS43VlnxA9E9hllkpSP5ellRDKjLLj7Lu9Wr6xA==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.4.0"
}
},
"node_modules/@mapbox/node-pre-gyp": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
@@ -833,6 +1248,12 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@marijn/find-cluster-break": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
"integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==",
"license": "MIT"
},
"node_modules/@nexus-terminal/backend": {
"resolved": "packages/backend",
"link": true
@@ -2032,6 +2453,37 @@
"@types/node": "*"
}
},
"node_modules/@uiw/codemirror-theme-vscode": {
"version": "4.23.12",
"resolved": "https://registry.npmjs.org/@uiw/codemirror-theme-vscode/-/codemirror-theme-vscode-4.23.12.tgz",
"integrity": "sha512-ePBaUQiixrpmSoZJWCGXUStKmcM8G0VBv3UqwPR+kNGBjqDife76Gbhv77izSeEI3zRPzL+683BOdclkvWnsMg==",
"license": "MIT",
"dependencies": {
"@uiw/codemirror-themes": "4.23.12"
},
"funding": {
"url": "https://jaywcjlove.github.io/#/sponsor"
}
},
"node_modules/@uiw/codemirror-themes": {
"version": "4.23.12",
"resolved": "https://registry.npmjs.org/@uiw/codemirror-themes/-/codemirror-themes-4.23.12.tgz",
"integrity": "sha512-8etEByfS9yttFZW0rcWhdZc7/JXJKRWlU5lHmJCI3GydZNGCzydNA+HtK9nWKpJUndVc58Q2sqSC5OIcwq8y6A==",
"license": "MIT",
"dependencies": {
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0"
},
"funding": {
"url": "https://jaywcjlove.github.io/#/sponsor"
},
"peerDependencies": {
"@codemirror/language": ">=6.0.0",
"@codemirror/state": ">=6.0.0",
"@codemirror/view": ">=6.0.0"
}
},
"node_modules/@vitejs/plugin-vue": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.6.2.tgz",
@@ -3760,6 +4212,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/crelt": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
"license": "MIT"
},
"node_modules/cross-env": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
@@ -8098,6 +8556,12 @@
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/style-mod": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==",
"license": "MIT"
},
"node_modules/superjson": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz",
@@ -9016,6 +9480,12 @@
"vue": "^3.0.1"
}
},
"node_modules/w3c-keyname": {
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
"license": "MIT"
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
@@ -9431,10 +9901,24 @@
"name": "@nexus-terminal/frontend",
"version": "0.7.13",
"dependencies": {
"@codemirror/lang-cpp": "^6.0.2",
"@codemirror/lang-go": "^6.0.1",
"@codemirror/lang-java": "^6.0.1",
"@codemirror/lang-json": "^6.0.1",
"@codemirror/lang-markdown": "^6.3.2",
"@codemirror/lang-php": "^6.0.1",
"@codemirror/lang-python": "^6.2.1",
"@codemirror/lang-rust": "^6.0.1",
"@codemirror/lang-sql": "^6.9.0",
"@codemirror/lang-xml": "^6.1.0",
"@codemirror/lang-yaml": "^6.1.2",
"@codemirror/legacy-modes": "^6.5.1",
"@fortawesome/fontawesome-free": "^6.7.2",
"@hcaptcha/vue3-hcaptcha": "^1.3.0",
"@lezer/markdown": "^1.4.3",
"@simplewebauthn/browser": "^9.0.1",
"@tailwindcss/vite": "^4.1.4",
"@uiw/codemirror-theme-vscode": "^4.23.12",
"@vscode/iconv-lite-umd": "^0.7.0",
"@vueuse/core": "^13.1.0",
"@xterm/addon-fit": "^0.10.0",
@@ -55,6 +55,9 @@ let terminalTextStrokeEnabledFound = false;
case 'editorFontSize':
settings.editorFontSize = parseInt(row.value, 10);
break;
case 'mobileEditorFontSize':
settings.mobileEditorFontSize = parseInt(row.value, 10);
break;
case 'terminalBackgroundImage':
settings.terminalBackgroundImage = row.value || undefined;
break;
@@ -122,6 +125,7 @@ case 'terminalTextStrokeEnabled':
terminalFontSize: settings.terminalFontSize ?? defaults.terminalFontSize,
terminalFontSizeMobile: settings.terminalFontSizeMobile ?? defaults.terminalFontSizeMobile,
editorFontSize: settings.editorFontSize ?? defaults.editorFontSize,
mobileEditorFontSize: settings.mobileEditorFontSize ?? defaults.mobileEditorFontSize,
editorFontFamily: settings.editorFontFamily ?? defaults.editorFontFamily,
terminalBackgroundImage: settings.terminalBackgroundImage ?? defaults.terminalBackgroundImage,
pageBackgroundImage: settings.pageBackgroundImage ?? defaults.pageBackgroundImage,
@@ -172,6 +176,7 @@ const getDefaultAppearanceSettings = (): Omit<AppearanceSettings, '_id'> => {
terminalFontSize: 14,
terminalFontSizeMobile: 14, // 移动端默认字体大小
editorFontSize: 14,
mobileEditorFontSize: 16, //移动端编辑器默认字体大小
editorFontFamily: 'Consolas, "Noto Sans SC", "Microsoft YaHei"',
terminalBackgroundImage: undefined,
pageBackgroundImage: undefined,
@@ -213,6 +218,7 @@ export const ensureDefaultSettingsExist = async (db: sqlite3.Database): Promise<
{ key: 'terminalFontSize', value: defaults.terminalFontSize },
{ key: 'terminalFontSizeMobile', value: defaults.terminalFontSizeMobile },
{ key: 'editorFontSize', value: defaults.editorFontSize },
{ key: 'mobileEditorFontSize', value: defaults.mobileEditorFontSize },
{ key: 'editorFontFamily', value: defaults.editorFontFamily },
{ key: 'terminalBackgroundImage', value: defaults.terminalBackgroundImage ?? '' }, // 数据库中使用空字符串
{ key: 'pageBackgroundImage', value: defaults.pageBackgroundImage ?? '' }, // 数据库中使用空字符串
@@ -114,6 +114,16 @@ export const updateSettings = async (settingsDto: UpdateAppearanceDto): Promise<
settingsDto.editorFontSize = size;
}
// 验证 mobileEditorFontSize (如果提供了)
if (settingsDto.mobileEditorFontSize !== undefined && settingsDto.mobileEditorFontSize !== null) {
const size = Number(settingsDto.mobileEditorFontSize);
if (isNaN(size) || size <= 0) {
throw new Error(`无效的移动端编辑器字体大小: ${settingsDto.mobileEditorFontSize}。必须是一个正数。`);
}
// 确保类型正确传递给仓库层
settingsDto.mobileEditorFontSize = size;
}
// 验证 editorFontFamily (如果提供了)
if (settingsDto.hasOwnProperty('editorFontFamily')) {
if (settingsDto.editorFontFamily === null) {
+14
View File
@@ -9,10 +9,24 @@
"preview": "vite preview"
},
"dependencies": {
"@codemirror/lang-cpp": "^6.0.2",
"@codemirror/lang-go": "^6.0.1",
"@codemirror/lang-java": "^6.0.1",
"@codemirror/lang-json": "^6.0.1",
"@codemirror/lang-markdown": "^6.3.2",
"@codemirror/lang-php": "^6.0.1",
"@codemirror/lang-python": "^6.2.1",
"@codemirror/lang-rust": "^6.0.1",
"@codemirror/lang-sql": "^6.9.0",
"@codemirror/lang-xml": "^6.1.0",
"@codemirror/lang-yaml": "^6.1.2",
"@codemirror/legacy-modes": "^6.5.1",
"@fortawesome/fontawesome-free": "^6.7.2",
"@hcaptcha/vue3-hcaptcha": "^1.3.0",
"@lezer/markdown": "^1.4.3",
"@simplewebauthn/browser": "^9.0.1",
"@tailwindcss/vite": "^4.1.4",
"@uiw/codemirror-theme-vscode": "^4.23.12",
"@vscode/iconv-lite-umd": "^0.7.0",
"@vueuse/core": "^13.1.0",
"@xterm/addon-fit": "^0.10.0",
@@ -0,0 +1,306 @@
<template>
<div ref="editorRef" class="codemirror-mobile-editor-container" :style="{ fontSize: currentFontSize + 'px', fontFamily: editorFontFamily }"></div>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch, shallowRef, computed } from 'vue';
import { EditorState, Compartment } from '@codemirror/state';
import { useAppearanceStore } from '../stores/appearance.store';
import { EditorView, keymap, lineNumbers, highlightActiveLineGutter, highlightActiveLine, drawSelection, dropCursor } from '@codemirror/view';
import { syntaxHighlighting, defaultHighlightStyle, indentOnInput, bracketMatching, foldGutter, foldKeymap } from '@codemirror/language';
import { vscodeDark } from '@uiw/codemirror-theme-vscode';
import { history, historyKeymap, defaultKeymap } from '@codemirror/commands';
import { autocompletion, closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
import { highlightSelectionMatches, searchKeymap, openSearchPanel } from '@codemirror/search'; // + Import search functionalities
const props = defineProps({
modelValue: {
type: String,
default: '',
},
language: {
type: String,
default: 'plaintext',
},
});
const emit = defineEmits(['update:modelValue', 'request-save']);
const appearanceStore = useAppearanceStore();
const editorRef = ref<HTMLDivElement | null>(null);
const view = shallowRef<EditorView | null>(null);
const languageCompartment = new Compartment();
const currentFontSize = ref(appearanceStore.currentMobileEditorFontSize);
const MIN_FONT_SIZE = 8;
const MAX_FONT_SIZE = 40;
let lastPinchDistance = 0;
const debounceTimeout = ref<number | null>(null);
const DEBOUNCE_DELAY = 500; // 500ms
const editorFontFamily = computed(() => appearanceStore.currentEditorFontFamily);
const getDistance = (touches: TouchList): number => {
if (touches.length < 2) return 0;
const touch1 = touches[0];
const touch2 = touches[1];
return Math.sqrt(
Math.pow(touch2.pageX - touch1.pageX, 2) +
Math.pow(touch2.pageY - touch1.pageY, 2)
);
};
const onTouchStart = (event: TouchEvent) => {
if (editorRef.value && editorRef.value.contains(event.target as Node)) {
if (event.touches.length === 2) {
event.preventDefault();
lastPinchDistance = getDistance(event.touches);
}
}
};
const debouncedSetMobileEditorFontSize = (size: number) => {
if (debounceTimeout.value !== null) {
clearTimeout(debounceTimeout.value);
}
debounceTimeout.value = window.setTimeout(() => {
appearanceStore.setMobileEditorFontSize(size);
}, DEBOUNCE_DELAY);
};
const onTouchMove = (event: TouchEvent) => {
if (editorRef.value && editorRef.value.contains(event.target as Node)) {
if (event.touches.length === 2) {
event.preventDefault();
const newPinchDistance = getDistance(event.touches);
if (lastPinchDistance > 0 && newPinchDistance > 0) {
const scale = newPinchDistance / lastPinchDistance;
let newFontSize = currentFontSize.value * scale;
newFontSize = Math.max(MIN_FONT_SIZE, Math.min(MAX_FONT_SIZE, newFontSize));
if (Math.abs(currentFontSize.value - newFontSize) > 0.1) {
currentFontSize.value = newFontSize;
debouncedSetMobileEditorFontSize(newFontSize);
}
}
if (newPinchDistance > 0) {
lastPinchDistance = newPinchDistance;
} else if (event.touches.length === 2) {
lastPinchDistance = getDistance(event.touches);
}
}
}
};
const onTouchEnd = (event: TouchEvent) => {
if (event.touches.length < 2) {
lastPinchDistance = 0;
}
};
const createEditorState = (doc: string, languageExtension: any) => {
return EditorState.create({
doc,
extensions: [
languageCompartment.of(languageExtension),
vscodeDark,
lineNumbers(),
history(),
highlightActiveLineGutter(),
foldGutter(),
drawSelection(),
dropCursor(),
EditorState.allowMultipleSelections.of(true),
indentOnInput(),
bracketMatching(),
highlightActiveLine(),
closeBrackets(),
autocompletion(),
highlightSelectionMatches(),
EditorView.updateListener.of((update) => {
if (update.docChanged) {
emit('update:modelValue', update.state.doc.toString());
}
}),
keymap.of([
...closeBracketsKeymap,
...defaultKeymap,
...historyKeymap,
...foldKeymap,
...searchKeymap, // + Add search keymap
{ key: "Mod-s", run: () => { emit('request-save'); return true; } }
]),
],
});
};
const getLanguageExtension = async (lang: string) => {
if (lang === 'javascript') {
const { javascript } = await import('@codemirror/lang-javascript');
return javascript();
}
if (lang === 'css') {
try {
const cssModule = await import('@codemirror/lang-css');
if (cssModule && typeof cssModule.css === 'function') {
const cssExtension = cssModule.css();
return cssExtension;
} else {
return [];
}
} catch (error) {
return [];
}
}
if (lang === 'html') {
const { html } = await import('@codemirror/lang-html');
return html();
}
if (lang === 'python') {
const { python } = await import('@codemirror/lang-python');
return python();
}
if (lang === 'java') {
const { java } = await import('@codemirror/lang-java');
return java();
}
if (lang === 'cpp') {
const { cpp } = await import('@codemirror/lang-cpp');
return cpp();
}
if (lang === 'php') {
const { php } = await import('@codemirror/lang-php');
return php();
}
if (lang === 'go') {
const { go } = await import('@codemirror/lang-go');
return go();
}
if (lang === 'rust') {
const { rust } = await import('@codemirror/lang-rust');
return rust();
}
if (lang === 'sql') {
const { sql } = await import('@codemirror/lang-sql');
return sql();
}
if (lang === 'json') {
const { json } = await import('@codemirror/lang-json');
return json();
}
if (lang === 'yaml') {
const { yaml } = await import('@codemirror/lang-yaml');
return yaml();
}
if (lang === 'xml') {
const { xml } = await import('@codemirror/lang-xml');
return xml();
}
if (lang === 'shell' || lang === 'bash') {
const { StreamLanguage } = await import('@codemirror/language');
const { shell } = await import('@codemirror/legacy-modes/mode/shell');
return StreamLanguage.define(shell);
}
if (lang === 'markdown') {
const { markdown, commonmarkLanguage } = await import('@codemirror/lang-markdown');
const { GFM } = await import('@lezer/markdown');
return markdown({
base: commonmarkLanguage,
extensions: GFM
});
}
if (lang === 'typescript' || lang === 'ts' || lang === 'tsx') {
const { javascript } = await import('@codemirror/lang-javascript');
return javascript({ typescript: true, jsx: true });
}
return [];
};
onMounted(async () => {
// Initialize font size from store
currentFontSize.value = appearanceStore.currentMobileEditorFontSize;
if (editorRef.value) {
const langExt = await getLanguageExtension(props.language);
console.log('[CodeMirrorMobileEditor DEBUG] onMounted - Initial language:', props.language, 'Fetched langExt:', langExt);
const startState = createEditorState(props.modelValue, langExt);
view.value = new EditorView({
state: startState,
parent: editorRef.value,
});
editorRef.value.addEventListener('touchstart', onTouchStart, { passive: false });
editorRef.value.addEventListener('touchmove', onTouchMove, { passive: false });
editorRef.value.addEventListener('touchend', onTouchEnd, { passive: false });
}
});
onBeforeUnmount(() => {
if (view.value) {
view.value.destroy();
view.value = null;
}
if (editorRef.value) {
editorRef.value.removeEventListener('touchstart', onTouchStart);
editorRef.value.removeEventListener('touchmove', onTouchMove);
editorRef.value.removeEventListener('touchend', onTouchEnd);
}
if (debounceTimeout.value !== null) {
clearTimeout(debounceTimeout.value);
}
});
watch(() => props.modelValue, (newValue) => {
if (view.value && newValue !== view.value.state.doc.toString()) {
view.value.dispatch({
changes: { from: 0, to: view.value.state.doc.length, insert: newValue },
});
}
});
watch(() => props.language, async (newLanguage, oldLanguage) => {
if (view.value && newLanguage !== oldLanguage) {
const langExt = await getLanguageExtension(newLanguage);
view.value.dispatch({
effects: languageCompartment.reconfigure(langExt)
});
}
});
watch(() => appearanceStore.currentMobileEditorFontSize, (newSize) => {
if (newSize !== currentFontSize.value) {
currentFontSize.value = newSize;
}
});
const openSearch = () => {
if (view.value) {
openSearchPanel(view.value);
}
};
defineExpose({
focus: () => view.value?.focus(),
openSearch, // + Expose openSearch method
});
</script>
<style scoped>
.codemirror-mobile-editor-container {
width: 100%;
height: 100%;
min-height: 200px;
text-align: left;
overflow: auto;
}
.codemirror-mobile-editor-container :deep(.cm-gutters) {
background-color: #1E1E1E !important;
color: #858585 !important;
border-right: 1px solid var(--border-color, #cccccc) !important;
}
.codemirror-mobile-editor-container :deep(.cm-selectionBackground) {
background-color: #5264ac !important;
}
</style>
@@ -3,6 +3,7 @@ import { computed, ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'
import { useI18n } from 'vue-i18n';
import { storeToRefs } from 'pinia';
import MonacoEditor from './MonacoEditor.vue';
import CodeMirrorMobileEditor from './CodeMirrorMobileEditor.vue'; // +++ Import new mobile editor
import FileEditorTabs from './FileEditorTabs.vue';
import { useFileEditorStore, type FileTab } from '../stores/fileEditor.store';
import { useSettingsStore } from '../stores/settings.store';
@@ -93,6 +94,7 @@ const startHeightPx = ref(0);
const minWidth = 400; //
const minHeight = 300; //
const encodingSelectRef = ref<HTMLSelectElement | null>(null); // +++ Ref for the select element +++
const codeMirrorMobileEditorRef = ref<InstanceType<typeof CodeMirrorMobileEditor> | null>(null); // +++ Ref for CodeMirrorMobileEditor +++
// --- ---
const popupStyle = computed(() => {
@@ -337,7 +339,7 @@ const handleCloseTab = (tabId: string) => {
const handleCloseOtherTabs = (targetTabId: string) => {
console.log(`[FileEditorOverlay] handleCloseOtherTabs called for target: ${targetTabId}`); // Add log
if (shareFileEditorTabsBoolean.value) {
closeOtherTabs(targetTabId); // action
closeOtherTabs(targetTabId);
} else {
const sessionId = popupFileInfo.value?.sessionId;
if (sessionId) {
@@ -351,7 +353,7 @@ const handleCloseOtherTabs = (targetTabId: string) => {
const handleCloseRightTabs = (targetTabId: string) => {
console.log(`[FileEditorOverlay] handleCloseRightTabs called for target: ${targetTabId}`); // Add log
if (shareFileEditorTabsBoolean.value) {
closeTabsToTheRight(targetTabId); // action
closeTabsToTheRight(targetTabId);
} else {
const sessionId = popupFileInfo.value?.sessionId;
if (sessionId) {
@@ -421,20 +423,19 @@ const handleEditorScroll = ({ scrollTop, scrollLeft }: { scrollTop: number; scro
const handleEditorFontSizeUpdate = (newSize: number) => {
appearanceStore.setEditorFontSize(newSize);
};
// +++ +++
const handleOpenSearch = () => {
if (codeMirrorMobileEditorRef.value) {
codeMirrorMobileEditorRef.value.openSearch();
}
};
// ()
const handleCloseContainer = () => {
//
// store activeTab
// if (activeTab.value?.isModified) { ... }
isVisible.value = false;
//
};
// ()
// const handleMinimizeContainer = () => {
// setEditorVisibility('minimized');
// };
// --- ---
const startResize = (event: MouseEvent) => {
@@ -478,20 +479,8 @@ watch(popupTrigger, () => {
const { filePath, sessionId } = popupFileInfo.value;
console.log(`[FileEditorOverlay] Triggered for file: ${filePath} in session: ${sessionId}`);
// store openFile/openFileInSession
// handleActivateTab
isVisible.value = true;
// --- () ---
// FileManager openFileInSession activeTabId
// FileManager openFile activeTabId
// setActiveTab store
// FileManager store action
// ()
// nextTick(() => { // DOM
// console.log(`[FileEditorOverlay] Popup shown. Current activeTabId: ${activeTabId.value}, Active Tab Object:`, activeTab.value);
// });
});
@@ -500,7 +489,6 @@ watch(activeTab, () => {
updateSelectWidth();
}, { immediate: true }); // immediate: true ensures it runs on initial load too
// +++ Watch for changes in the selected encoding to update width +++
watch(currentSelectedEncoding, () => {
updateSelectWidth();
});
@@ -557,6 +545,15 @@ onBeforeUnmount(() => {
<span v-if="currentTabSaveStatus === 'saving'" class="save-status saving">{{ t('fileManager.saving') }}...</span>
<span v-if="currentTabSaveStatus === 'success'" class="save-status success"> {{ t('fileManager.saveSuccess') }}</span>
<span v-if="currentTabSaveStatus === 'error'" class="save-status error"> {{ t('fileManager.saveError') }}: {{ currentTabSaveError }}</span>
<!-- +++ 移动端搜索按钮 (Font Awesome) +++ -->
<button
v-if="props.isMobile && activeTab && !currentTabIsLoading"
@click="handleOpenSearch"
class="search-btn"
:title="t('fileManager.actions.search', 'Search')"
>
<i class="fas fa-search"></i>
</button>
<button @click="handleSaveRequest" :disabled="currentTabIsSaving || currentTabIsLoading || !!currentTabLoadingError || !activeTab" class="save-btn">
{{ t('fileManager.actions.save') }}
</button>
@@ -575,9 +572,11 @@ onBeforeUnmount(() => {
<div class="editor-content-area">
<div v-if="currentTabIsLoading" class="editor-loading">{{ t('fileManager.loadingFile') }}</div>
<div v-else-if="currentTabLoadingError" class="editor-error">{{ currentTabLoadingError }}</div>
<!-- Desktop Editor -->
<MonacoEditor
v-else-if="activeTab"
:key="activeTab.id"
v-else-if="activeTab && !props.isMobile"
:key="`monaco-${activeTab.id}`"
v-model="activeEditorContent"
:language="currentTabLanguage"
:font-family="currentEditorFontFamily"
@@ -586,9 +585,19 @@ onBeforeUnmount(() => {
:font-size="currentEditorFontSize"
@request-save="handleSaveRequest"
@update:fontSize="handleEditorFontSizeUpdate"
:initialScrollTop="activeTab?.scrollTop ?? 0"
:initialScrollLeft="activeTab?.scrollLeft ?? 0"
@update:scrollPosition="handleEditorScroll"
:initialScrollTop="activeTab?.scrollTop ?? 0"
:initialScrollLeft="activeTab?.scrollLeft ?? 0"
@update:scrollPosition="handleEditorScroll"
/>
<!-- Mobile Editor -->
<CodeMirrorMobileEditor
v-else-if="activeTab && props.isMobile"
:key="`cm-${activeTab.id}`"
v-model="activeEditorContent"
:language="currentTabLanguage"
class="editor-instance"
@request-save="handleSaveRequest"
ref="codeMirrorMobileEditorRef"
/>
<!-- 如果容器可见但没有活动标签页 -->
<div v-else class="editor-placeholder">{{ t('fileManager.selectFileToEdit') }}</div>
@@ -805,6 +814,29 @@ onBeforeUnmount(() => {
background-color: #45a049;
}
.search-btn {
display: flex;
align-items: center;
justify-content: center;
width: 1.75rem;
height: 1.75rem;
background-color: transparent;
border: none;
border-radius: 0.25rem;
cursor: pointer;
transition: background-color 0.2s, color 0.2s;
padding: 0;
color: #ccc;
}
.search-btn:hover {
background-color: rgba(0, 0, 0, 0.1);
color: #f0f0f0;
}
.search-btn i {
font-size: 1rem;
line-height: 1;
}
.save-status {
font-size: 0.9em;
padding: 0.2rem 0.5rem;
@@ -838,33 +870,7 @@ onBeforeUnmount(() => {
}
/* 最小化状态样式 (可选) */
/*
.editor-minimized-bar {
position: fixed;
bottom: 0;
left: 50%;
transform: translateX(-50%);
background-color: #333;
color: #f0f0f0;
padding: 0.5rem 1rem;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
cursor: pointer;
z-index: 1001;
display: flex;
align-items: center;
gap: 1rem;
}
.editor-minimized-bar button {
background: none;
border: none;
color: #ccc;
cursor: pointer;
}
*/
/* +++ 编码选择器样式 (copied from FileEditorContainer) +++ */
.encoding-select-wrapper {
display: inline-block; /* 让 wrapper 包裹内容 */
vertical-align: middle; /* 垂直居中对齐 */
@@ -879,7 +885,6 @@ onBeforeUnmount(() => {
font-size: 0.85em;
cursor: pointer;
outline: none;
/* width: auto; */ /* JS will control width via style property */
}
.encoding-select:hover {
@@ -29,7 +29,7 @@ const props = defineProps({
type: String,
default: 'Consolas, "Courier New", monospace',
},
fontSize: { // prop
fontSize: {
type: Number,
default: 14, //
},
@@ -129,6 +129,12 @@ export const useAppearanceStore = defineStore('appearance', () => {
const currentEditorFontFamily = computed<string>(() => {
return appearanceSettings.value.editorFontFamily || 'Consolas, "Noto Sans SC", "Microsoft YaHei"'; // 提供默认值
});
// 当前移动端编辑器字体大小
const currentMobileEditorFontSize = computed<number>(() => {
const size = appearanceSettings.value.mobileEditorFontSize;
return typeof size === 'number' && size > 0 ? size : 16; // 默认 16
});
// 终端背景是否启用
const isTerminalBackgroundEnabled = computed<boolean>(() => {
@@ -342,6 +348,14 @@ export const useAppearanceStore = defineStore('appearance', () => {
async function setEditorFontFamily(fontFamily: string) {
await updateAppearanceSettings({ editorFontFamily: fontFamily });
}
/**
*
* @param size ()
*/
async function setMobileEditorFontSize(size: number) {
await updateAppearanceSettings({ mobileEditorFontSize: size });
}
/**
*
@@ -890,7 +904,8 @@ export const useAppearanceStore = defineStore('appearance', () => {
terminalFontSizeDesktop, // + 用于在设置中分别显示/设置桌面端字号
terminalFontSizeMobile, // + 用于在设置中分别显示/设置移动端字号
currentEditorFontSize,
currentEditorFontFamily, // 新增
currentMobileEditorFontSize, // 移动端编辑器字号 getter
currentEditorFontFamily,
pageBackgroundImage,
terminalBackgroundImage,
currentTerminalBackgroundOverlayOpacity,
@@ -904,7 +919,8 @@ export const useAppearanceStore = defineStore('appearance', () => {
setTerminalFontSize, // 设置桌面端字体大小
setTerminalFontSizeMobile, // + 设置移动端字体大小
setEditorFontSize,
setEditorFontFamily, // 新增
setMobileEditorFontSize, // 设置移动端编辑器字号 action
setEditorFontFamily,
setTerminalBackgroundEnabled,
createTerminalTheme,
updateTerminalTheme,
@@ -11,7 +11,8 @@ export interface AppearanceSettings {
terminalFontSizeMobile?: number; // 移动端字体大小
terminalBackgroundImage?: string;
pageBackgroundImage?: string;
editorFontSize?: number;
editorFontSize?: number; // 桌面端编辑器字号
mobileEditorFontSize?: number; // 移动端编辑器字号
editorFontFamily?: string | null; // Monaco Editor 字体偏好
terminalBackgroundEnabled?: boolean; // 终端背景是否启用
terminalBackgroundOverlayOpacity?: number; // 终端背景蒙版透明度 (0-1)