diff --git a/builder/Cargo.lock b/builder/Cargo.lock index fd3f9f36..aee9ee38 100644 --- a/builder/Cargo.lock +++ b/builder/Cargo.lock @@ -80,9 +80,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.35" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" +checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04" dependencies = [ "clap_builder", "clap_derive", @@ -90,9 +90,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.35" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" +checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5" dependencies = [ "anstream", "anstyle", diff --git a/client/package-lock.json b/client/package-lock.json index 2551b980..e8c78617 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,12 +1,12 @@ { "name": "codechat-editor-client", - "version": "0.1.16", + "version": "0.1.17", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "codechat-editor-client", - "version": "0.1.16", + "version": "0.1.17", "license": "GPL-3.0-or-later", "dependencies": { "@codemirror/lang-cpp": "^6", @@ -773,9 +773,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz", - "integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.0.tgz", + "integrity": "sha512-WhCn7Z7TauhBtmzhvKpoQs0Wwb/kBcy4CwpuI0/eEIr2Lx2auxmulAzLr91wVZJaz47iUZdkXOK7WlAfxGKCnA==", "dev": true, "license": "MIT", "dependencies": { @@ -1449,16 +1449,16 @@ } }, "node_modules/@pkgr/core": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.2.tgz", - "integrity": "sha512-25L86MyPvnlQoX2MTIV2OiUcb6vJ6aRbFa9pbwByn95INKD5mFH2smgjDhq+fwJoqAgvgbdJLj6Tz7V9X5CFAQ==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.3.tgz", + "integrity": "sha512-yMV8bb9prWI21N6FsrnPCbhoYb8UUvYCDGoSvPHBloVC095Ef2ker43hzXkJ6TpJPw53S8FeFYkARa7GGIGwxg==", "dev": true, "license": "MIT", "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://opencollective.com/unts" + "url": "https://opencollective.com/pkgr" } }, "node_modules/@rtsao/scc": { @@ -1780,9 +1780,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.14.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz", - "integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==", + "version": "22.14.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz", + "integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==", "dev": true, "license": "MIT", "dependencies": { @@ -1797,17 +1797,17 @@ "optional": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.29.1.tgz", - "integrity": "sha512-ba0rr4Wfvg23vERs3eB+P3lfj2E+2g3lhWcCVukUuhtcdUx5lSIFZlGFEBHKr+3zizDa/TvZTptdNHVZWAkSBg==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.30.1.tgz", + "integrity": "sha512-v+VWphxMjn+1t48/jO4t950D6KR8JaJuNXzi33Ve6P8sEmPr5k6CEXjdGwT6+LodVnEa91EQCtwjWNUCPweo+Q==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.29.1", - "@typescript-eslint/type-utils": "8.29.1", - "@typescript-eslint/utils": "8.29.1", - "@typescript-eslint/visitor-keys": "8.29.1", + "@typescript-eslint/scope-manager": "8.30.1", + "@typescript-eslint/type-utils": "8.30.1", + "@typescript-eslint/utils": "8.30.1", + "@typescript-eslint/visitor-keys": "8.30.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1827,16 +1827,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.29.1.tgz", - "integrity": "sha512-zczrHVEqEaTwh12gWBIJWj8nx+ayDcCJs06yoNMY0kwjMWDM6+kppljY+BxWI06d2Ja+h4+WdufDcwMnnMEWmg==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.30.1.tgz", + "integrity": "sha512-H+vqmWwT5xoNrXqWs/fesmssOW70gxFlgcMlYcBaWNPIEWDgLa4W9nkSPmhuOgLnXq9QYgkZ31fhDyLhleCsAg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.29.1", - "@typescript-eslint/types": "8.29.1", - "@typescript-eslint/typescript-estree": "8.29.1", - "@typescript-eslint/visitor-keys": "8.29.1", + "@typescript-eslint/scope-manager": "8.30.1", + "@typescript-eslint/types": "8.30.1", + "@typescript-eslint/typescript-estree": "8.30.1", + "@typescript-eslint/visitor-keys": "8.30.1", "debug": "^4.3.4" }, "engines": { @@ -1852,14 +1852,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.29.1.tgz", - "integrity": "sha512-2nggXGX5F3YrsGN08pw4XpMLO1Rgtnn4AzTegC2MDesv6q3QaTU5yU7IbS1tf1IwCR0Hv/1EFygLn9ms6LIpDA==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.30.1.tgz", + "integrity": "sha512-+C0B6ChFXZkuaNDl73FJxRYT0G7ufVPOSQkqkpM/U198wUwUFOtgo1k/QzFh1KjpBitaK7R1tgjVz6o9HmsRPg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.29.1", - "@typescript-eslint/visitor-keys": "8.29.1" + "@typescript-eslint/types": "8.30.1", + "@typescript-eslint/visitor-keys": "8.30.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1870,14 +1870,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.29.1.tgz", - "integrity": "sha512-DkDUSDwZVCYN71xA4wzySqqcZsHKic53A4BLqmrWFFpOpNSoxX233lwGu/2135ymTCR04PoKiEEEvN1gFYg4Tw==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.30.1.tgz", + "integrity": "sha512-64uBF76bfQiJyHgZISC7vcNz3adqQKIccVoKubyQcOnNcdJBvYOILV1v22Qhsw3tw3VQu5ll8ND6hycgAR5fEA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.29.1", - "@typescript-eslint/utils": "8.29.1", + "@typescript-eslint/typescript-estree": "8.30.1", + "@typescript-eslint/utils": "8.30.1", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, @@ -1894,9 +1894,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.29.1.tgz", - "integrity": "sha512-VT7T1PuJF1hpYC3AGm2rCgJBjHL3nc+A/bhOp9sGMKfi5v0WufsX/sHCFBfNTx2F+zA6qBc/PD0/kLRLjdt8mQ==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.30.1.tgz", + "integrity": "sha512-81KawPfkuulyWo5QdyG/LOKbspyyiW+p4vpn4bYO7DM/hZImlVnFwrpCTnmNMOt8CvLRr5ojI9nU1Ekpw4RcEw==", "dev": true, "license": "MIT", "engines": { @@ -1908,14 +1908,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.29.1.tgz", - "integrity": "sha512-l1enRoSaUkQxOQnbi0KPUtqeZkSiFlqrx9/3ns2rEDhGKfTa+88RmXqedC1zmVTOWrLc2e6DEJrTA51C9iLH5g==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.30.1.tgz", + "integrity": "sha512-kQQnxymiUy9tTb1F2uep9W6aBiYODgq5EMSk6Nxh4Z+BDUoYUSa029ISs5zTzKBFnexQEh71KqwjKnRz58lusQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.29.1", - "@typescript-eslint/visitor-keys": "8.29.1", + "@typescript-eslint/types": "8.30.1", + "@typescript-eslint/visitor-keys": "8.30.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -1935,16 +1935,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.29.1.tgz", - "integrity": "sha512-QAkFEbytSaB8wnmB+DflhUPz6CLbFWE2SnSCrRMEa+KnXIzDYbpsn++1HGvnfAsUY44doDXmvRkO5shlM/3UfA==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.30.1.tgz", + "integrity": "sha512-T/8q4R9En2tcEsWPQgB5BQ0XJVOtfARcUvOa8yJP3fh9M/mXraLxZrkCfGb6ChrO/V3W+Xbd04RacUEqk1CFEQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.29.1", - "@typescript-eslint/types": "8.29.1", - "@typescript-eslint/typescript-estree": "8.29.1" + "@typescript-eslint/scope-manager": "8.30.1", + "@typescript-eslint/types": "8.30.1", + "@typescript-eslint/typescript-estree": "8.30.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1959,13 +1959,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.29.1.tgz", - "integrity": "sha512-RGLh5CRaUEf02viP5c1Vh1cMGffQscyHe7HPAzGpfmfflFg1wUz2rYxd+OZqwpeypYvZ8UxSxuIpF++fmOzEcg==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.30.1.tgz", + "integrity": "sha512-aEhgas7aJ6vZnNFC7K4/vMGDGyOiqWcYZPpIWrTKuTAlsvDNKy2GFDqh9smL+iq069ZvR0YzEeq0B8NJlLzjFA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.29.1", + "@typescript-eslint/types": "8.30.1", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -5821,13 +5821,13 @@ } }, "node_modules/synckit": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.3.tgz", - "integrity": "sha512-szhWDqNNI9etJUvbZ1/cx1StnZx8yMmFxme48SwR4dty4ioSY50KEZlpv0qAfgc1fpRzuh9hBXEzoCpJ779dLg==", + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.4.tgz", + "integrity": "sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ==", "dev": true, "license": "MIT", "dependencies": { - "@pkgr/core": "^0.2.1", + "@pkgr/core": "^0.2.3", "tslib": "^2.8.1" }, "engines": { diff --git a/client/package.json b/client/package.json index 251f34af..6fb4c362 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "codechat-editor-client", - "version": "0.1.16", + "version": "0.1.17", "description": "The CodeChat Editor Client, part of a web-based literate programming editor (the CodeChat Editor).", "homepage": "https://github.com/bjones1/CodeChat_Editor", "type": "module", diff --git a/client/src/turndown/turndown.browser.es.js b/client/src/turndown/turndown.browser.es.js index 2217b313..f0ed1bbc 100644 --- a/client/src/turndown/turndown.browser.es.js +++ b/client/src/turndown/turndown.browser.es.js @@ -302,10 +302,11 @@ rules.heading = { filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], replacement: function (content, node, options) { - content = wrapContent(content, node, options); var hLevel = Number(node.nodeName.charAt(1)); if (options.headingStyle === 'setext' && hLevel < 3) { + // Only wrap setext headings -- atx heading don't work wrapped. + content = wrapContent(content, node, options); // Split the contents into lines, then find the longest line length. const splitContent = content.split(/\r\n|\n|\r/); // From [SO](https://stackoverflow.com/a/43304999/16038919). diff --git a/docs/changelog.md b/docs/changelog.md index b2d5d2c2..66fe61e0 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -21,6 +21,9 @@ Changelog * [Github master](https://github.com/bjones1/CodeChat_Editor): * No changes. +* v0.1.17, 2025-Apr-14: + * Fix heading level 3 and below word wrapping. + * Correctly handle unclosed fenced code blocks. * v0.1.16, 2025-Apr-11: * Fix to allow running inside a GitHub Codespace. * Add: new command-line option to open a file/directory -- diff --git a/extensions/VSCode/package-lock.json b/extensions/VSCode/package-lock.json index 243bed49..b03009a8 100644 --- a/extensions/VSCode/package-lock.json +++ b/extensions/VSCode/package-lock.json @@ -1,12 +1,12 @@ { "name": "codechat-editor-client", - "version": "0.1.16", + "version": "0.1.17", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "codechat-editor-client", - "version": "0.1.16", + "version": "0.1.17", "license": "GPL-3.0-only", "dependencies": { "escape-html": "^1", @@ -205,9 +205,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz", - "integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.0.tgz", + "integrity": "sha512-WhCn7Z7TauhBtmzhvKpoQs0Wwb/kBcy4CwpuI0/eEIr2Lx2auxmulAzLr91wVZJaz47iUZdkXOK7WlAfxGKCnA==", "dev": true, "license": "MIT", "dependencies": { @@ -548,9 +548,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.14.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz", - "integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==", + "version": "22.14.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz", + "integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==", "dev": true, "license": "MIT", "dependencies": { @@ -575,17 +575,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.29.1.tgz", - "integrity": "sha512-ba0rr4Wfvg23vERs3eB+P3lfj2E+2g3lhWcCVukUuhtcdUx5lSIFZlGFEBHKr+3zizDa/TvZTptdNHVZWAkSBg==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.30.1.tgz", + "integrity": "sha512-v+VWphxMjn+1t48/jO4t950D6KR8JaJuNXzi33Ve6P8sEmPr5k6CEXjdGwT6+LodVnEa91EQCtwjWNUCPweo+Q==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.29.1", - "@typescript-eslint/type-utils": "8.29.1", - "@typescript-eslint/utils": "8.29.1", - "@typescript-eslint/visitor-keys": "8.29.1", + "@typescript-eslint/scope-manager": "8.30.1", + "@typescript-eslint/type-utils": "8.30.1", + "@typescript-eslint/utils": "8.30.1", + "@typescript-eslint/visitor-keys": "8.30.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -605,16 +605,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.29.1.tgz", - "integrity": "sha512-zczrHVEqEaTwh12gWBIJWj8nx+ayDcCJs06yoNMY0kwjMWDM6+kppljY+BxWI06d2Ja+h4+WdufDcwMnnMEWmg==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.30.1.tgz", + "integrity": "sha512-H+vqmWwT5xoNrXqWs/fesmssOW70gxFlgcMlYcBaWNPIEWDgLa4W9nkSPmhuOgLnXq9QYgkZ31fhDyLhleCsAg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.29.1", - "@typescript-eslint/types": "8.29.1", - "@typescript-eslint/typescript-estree": "8.29.1", - "@typescript-eslint/visitor-keys": "8.29.1", + "@typescript-eslint/scope-manager": "8.30.1", + "@typescript-eslint/types": "8.30.1", + "@typescript-eslint/typescript-estree": "8.30.1", + "@typescript-eslint/visitor-keys": "8.30.1", "debug": "^4.3.4" }, "engines": { @@ -630,14 +630,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.29.1.tgz", - "integrity": "sha512-2nggXGX5F3YrsGN08pw4XpMLO1Rgtnn4AzTegC2MDesv6q3QaTU5yU7IbS1tf1IwCR0Hv/1EFygLn9ms6LIpDA==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.30.1.tgz", + "integrity": "sha512-+C0B6ChFXZkuaNDl73FJxRYT0G7ufVPOSQkqkpM/U198wUwUFOtgo1k/QzFh1KjpBitaK7R1tgjVz6o9HmsRPg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.29.1", - "@typescript-eslint/visitor-keys": "8.29.1" + "@typescript-eslint/types": "8.30.1", + "@typescript-eslint/visitor-keys": "8.30.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -648,14 +648,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.29.1.tgz", - "integrity": "sha512-DkDUSDwZVCYN71xA4wzySqqcZsHKic53A4BLqmrWFFpOpNSoxX233lwGu/2135ymTCR04PoKiEEEvN1gFYg4Tw==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.30.1.tgz", + "integrity": "sha512-64uBF76bfQiJyHgZISC7vcNz3adqQKIccVoKubyQcOnNcdJBvYOILV1v22Qhsw3tw3VQu5ll8ND6hycgAR5fEA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.29.1", - "@typescript-eslint/utils": "8.29.1", + "@typescript-eslint/typescript-estree": "8.30.1", + "@typescript-eslint/utils": "8.30.1", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, @@ -672,9 +672,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.29.1.tgz", - "integrity": "sha512-VT7T1PuJF1hpYC3AGm2rCgJBjHL3nc+A/bhOp9sGMKfi5v0WufsX/sHCFBfNTx2F+zA6qBc/PD0/kLRLjdt8mQ==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.30.1.tgz", + "integrity": "sha512-81KawPfkuulyWo5QdyG/LOKbspyyiW+p4vpn4bYO7DM/hZImlVnFwrpCTnmNMOt8CvLRr5ojI9nU1Ekpw4RcEw==", "dev": true, "license": "MIT", "engines": { @@ -686,14 +686,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.29.1.tgz", - "integrity": "sha512-l1enRoSaUkQxOQnbi0KPUtqeZkSiFlqrx9/3ns2rEDhGKfTa+88RmXqedC1zmVTOWrLc2e6DEJrTA51C9iLH5g==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.30.1.tgz", + "integrity": "sha512-kQQnxymiUy9tTb1F2uep9W6aBiYODgq5EMSk6Nxh4Z+BDUoYUSa029ISs5zTzKBFnexQEh71KqwjKnRz58lusQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.29.1", - "@typescript-eslint/visitor-keys": "8.29.1", + "@typescript-eslint/types": "8.30.1", + "@typescript-eslint/visitor-keys": "8.30.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -713,16 +713,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.29.1.tgz", - "integrity": "sha512-QAkFEbytSaB8wnmB+DflhUPz6CLbFWE2SnSCrRMEa+KnXIzDYbpsn++1HGvnfAsUY44doDXmvRkO5shlM/3UfA==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.30.1.tgz", + "integrity": "sha512-T/8q4R9En2tcEsWPQgB5BQ0XJVOtfARcUvOa8yJP3fh9M/mXraLxZrkCfGb6ChrO/V3W+Xbd04RacUEqk1CFEQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.29.1", - "@typescript-eslint/types": "8.29.1", - "@typescript-eslint/typescript-estree": "8.29.1" + "@typescript-eslint/scope-manager": "8.30.1", + "@typescript-eslint/types": "8.30.1", + "@typescript-eslint/typescript-estree": "8.30.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -737,13 +737,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.29.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.29.1.tgz", - "integrity": "sha512-RGLh5CRaUEf02viP5c1Vh1cMGffQscyHe7HPAzGpfmfflFg1wUz2rYxd+OZqwpeypYvZ8UxSxuIpF++fmOzEcg==", + "version": "8.30.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.30.1.tgz", + "integrity": "sha512-aEhgas7aJ6vZnNFC7K4/vMGDGyOiqWcYZPpIWrTKuTAlsvDNKy2GFDqh9smL+iq069ZvR0YzEeq0B8NJlLzjFA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.29.1", + "@typescript-eslint/types": "8.30.1", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -4483,9 +4483,9 @@ } }, "node_modules/ovsx": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.10.1.tgz", - "integrity": "sha512-8i7+MJMMeq73m1zPEIClSFe17SNuuzU5br7G77ZIfOC24elB4pGQs0N1qRd+gnnbyhL5Qu96G21nFOVOBa2OBg==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.10.2.tgz", + "integrity": "sha512-osLwIOz5Uu1ePvYYSjKw05bkCZo2j/ydQLjm3uO7bCfstyFFzmWyzMGTAL3wJpI4qpo1S47Y52+q09h9A2ZRkQ==", "dev": true, "license": "EPL-2.0", "dependencies": { diff --git a/extensions/VSCode/package.json b/extensions/VSCode/package.json index 0f05b251..84461353 100644 --- a/extensions/VSCode/package.json +++ b/extensions/VSCode/package.json @@ -1,6 +1,6 @@ { "name": "codechat-editor-client", - "version": "0.1.16", + "version": "0.1.17", "publisher": "CodeChat", "engines": { "vscode": "^1.61.0" diff --git a/server/Cargo.lock b/server/Cargo.lock index e01b0488..9097a969 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -329,9 +329,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "arc-swap" @@ -499,9 +499,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.18" +version = "1.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" +checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" dependencies = [ "jobserver", "libc", @@ -530,9 +530,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.35" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" +checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04" dependencies = [ "clap_builder", "clap_derive", @@ -540,9 +540,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.35" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" +checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5" dependencies = [ "anstream", "anstyle", @@ -570,7 +570,7 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "codechat-editor-server" -version = "0.1.16" +version = "0.1.17" dependencies = [ "actix-files", "actix-http", @@ -702,9 +702,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "deranged" @@ -1562,9 +1562,9 @@ dependencies = [ [[package]] name = "minreq" -version = "2.13.3" +version = "2.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567496f13503d6cae8c9f961f34536850275f396307d7a6b981eef1464032f53" +checksum = "f0d2aaba477837b46ec1289588180fabfccf0c3b1d1a0c6b1866240cd6cd5ce9" dependencies = [ "log", ] diff --git a/server/Cargo.toml b/server/Cargo.toml index ff56c08d..4779efb4 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -31,7 +31,7 @@ license = "GPL-3.0-only" name = "codechat-editor-server" readme = "../README.md" repository = "https://github.com/bjones1/CodeChat_Editor" -version = "0.1.16" +version = "0.1.17" # This library allows other packages to use core CodeChat Editor features. [lib] diff --git a/server/src/main.rs b/server/src/main.rs index f8606dfa..d16c6b82 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -115,7 +115,9 @@ impl Cli { let body = response.as_str().unwrap_or("Non-text body"); if status_code == 200 && body == "pong" { println!("Server started."); - // Open a web browser if requested. + // Open a web browser if requested. TODO: show + // an error if running in a Codespace, since + // this doesn't work. if let Some(open_path) = open { let address = get_server_url(self.port)?; let open_path = fs::canonicalize(open_path)?; @@ -132,7 +134,8 @@ impl Cli { } } Err(err) => { - // Use this to skip the print from a nested if statement. + // Use this to skip the print from a nested if + // statement. 'err_print: { // Ignore a connection refused error. if let minreq::Error::IoError(io_error) = &err { @@ -141,7 +144,6 @@ impl Cli { } } eprintln!("Failed to connect to server: {err}"); - break 'err_print; } } } diff --git a/server/src/processing.rs b/server/src/processing.rs index 400b6dd0..943a49fc 100644 --- a/server/src/processing.rs +++ b/server/src/processing.rs @@ -48,8 +48,7 @@ use crate::lexer::{CodeDocBlock, DocBlock, LanguageLexerCompiled, source_lexer}; // Data structures // --------------- // -// ### Translation between a local (traditional) source file and its web-editable, -// client-side representation +// ### Translation between a local (traditional) source file and its web-editable, client-side representation // // There are three ways that a source file is represented: // @@ -76,7 +75,8 @@ pub struct CodeChatForWeb { /// of comment delimiters? #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct SourceFileMetadata { - /// The lexer used to transforms source code into code and doc blocks and vice versa. + /// The lexer used to transforms source code into code and doc blocks and + /// vice versa. pub mode: String, } @@ -125,8 +125,8 @@ pub enum TranslationResults { pub enum TranslationResultsString { /// This is a binary file; it must be viewed raw or using the simple viewer. Binary, - /// This file is unknown to the CodeChat - /// Editor. It must be viewed raw or using the simple viewer. + /// This file is unknown to the CodeChat Editor. It must be viewed raw or + /// using the simple viewer. Unknown, /// This is a CodeChat Editor file but it contains errors that prevent its /// translation. The string contains the error message. @@ -145,12 +145,52 @@ pub enum TranslationResultsString { lazy_static! { /// Match the lexer directive in a source file. static ref LEXER_DIRECTIVE: Regex = Regex::new(r"CodeChat Editor lexer: (\w+)").unwrap(); - /// Match the doc block separator string translated from Markdown to HTML as - /// itself, or when inside a fenced code block. - static ref DOC_BLOCK_SEPARATOR_STRING_REGEX: Regex = Regex::new("\n|<CodeChatEditor-separator/>\n").unwrap(); + /// If this matches, it means an + /// unterminated fenced code block. This should be replaced with the + /// `` terminator. + static ref DOC_BLOCK_SEPARATOR_BROKEN_FENCE: Regex = Regex::new(concat!( + // Allow the `.` wildcard to match newlines. + "(?s)", + // The first `` will be munged when a fenced code + // block isn't closed. + "<CodeChatEditor-fence>\n", + // Non-greedy wildcard -- match the first separator, so we don't munch + // multiple `DOC_BLOCK_SEPARATOR_STRING`s in one replacement. + ".*?", + "\n")).unwrap(); } -const DOC_BLOCK_SEPARATOR_STRING: &str = "\n\n\n"; +// Use this as a way to end unterminated fenced code blocks. If a fenced block +// isn't terminated, then the HTML tag is ignored, meaning the line of `---` or +// `~~~` characters stop it. If the fenced block is terminated, then the HTML +// tags prevent starting a code block and can be removed. Note that this only +// supports fenced code blocks with an opening code fence of 23 characters or +// less (which should cover most cases). To allow more, we'd need to know the +// length of the opening code fence, which is hard to find. +const DOC_BLOCK_SEPARATOR_STRING: &str = r#" + +``````````````````````` + +~~~~~~~~~~~~~~~~~~~~~~~ + + + +"#; + +// After converting Markdown to HTML, this can be used to split doc blocks +// apart. +const DOC_BLOCK_SEPARATOR_SPLIT_STRING: &str = "\n"; +// Correctly terminated fenced code blocks produce this, which can be removed +// from the HTML produced by Markdown conversion. +const DOC_BLOCK_SEPARATOR_REMOVE_FENCE: &str = r#" +``````````````````````` + +~~~~~~~~~~~~~~~~~~~~~~~ + +"#; +// The replacement string for the `DOC_BLOCK_SEPARATOR_BROKEN_FENCE` regex. +const DOC_BLOCK_SEPARATOR_MENDED_FENCE: &str = "\n\n"; +// // Determine if the provided file is part of a project. // ---------------------------------------------------- @@ -478,14 +518,20 @@ pub fn source_to_codechat_for_web( // string. .collect::>() .join(DOC_BLOCK_SEPARATOR_STRING); + + // Convert the Markdown to HTML. let html = markdown_to_html(&doc_contents); - // Now that we have HTML, process it. TODO. + + // Break it back into doc blocks: // - // After processing by Markdown, the doc block separator string may - // be (mostly) unchanged; however, if there's an unterminated fenced - // code block, then HTML entities replaces angle brackets. Match on - // either case. - let mut doc_block_contents_iter = DOC_BLOCK_SEPARATOR_STRING_REGEX.split(&html); + // 1. Mend broken fences. + let html = DOC_BLOCK_SEPARATOR_BROKEN_FENCE + .replace_all(&html, DOC_BLOCK_SEPARATOR_MENDED_FENCE); + // 2. Remove good fences. + let html = html.replace(DOC_BLOCK_SEPARATOR_REMOVE_FENCE, ""); + // 3. Split on the separator. + let mut doc_block_contents_iter = html.split(DOC_BLOCK_SEPARATOR_SPLIT_STRING); + // // Translate each `CodeDocBlock` to its `CodeMirror` equivalent. for code_or_doc_block in code_doc_block_arr { @@ -1367,6 +1413,18 @@ mod tests { ] )) ); + assert_eq!( + source_to_codechat_for_web("// ~~~\n\n//\n\n//", &"cpp".to_string(), false, false), + TranslationResults::CodeChat(build_codechat_for_web( + "c_cpp", + "\n\n\n\n", + vec![ + build_codemirror_doc_block(0, 0, "", "//", "
\n
\n"), + build_codemirror_doc_block(2, 2, "", "//", ""), + build_codemirror_doc_block(4, 4, "", "//", "") + ] + )) + ); // Test Unicode characters in code. assert_eq!( @@ -1388,15 +1446,70 @@ mod tests { )) ); - // Test a fenced code block that's unterminated. + // Test a fenced code block that's unterminated. See [fence + // mending](#fence-mending). + assert_eq!( + source_to_codechat_for_web("/* ``` foo\n*/\n// Test", &"cpp".to_string(), false, false), + TranslationResults::CodeChat(build_codechat_for_web( + "c_cpp", + "\n\n\n", + vec![ + build_codemirror_doc_block( + 0, + 1, + "", + "/*", + "
\n\n
\n" + ), + build_codemirror_doc_block(2, 2, "", "//", "

Test

\n"), + ] + )) + ); + // Test the other code fence character (the tilde). + assert_eq!( + source_to_codechat_for_web( + "/* ~~~~~~~ foo\n*/\n// Test", + &"cpp".to_string(), + false, + false + ), + TranslationResults::CodeChat(build_codechat_for_web( + "c_cpp", + "\n\n\n", + vec![ + build_codemirror_doc_block( + 0, + 1, + "", + "/*", + "
\n\n
\n" + ), + build_codemirror_doc_block(2, 2, "", "//", "

Test

\n"), + ] + )) + ); + // Test multiple unterminated fenced code blocks. + assert_eq!( + source_to_codechat_for_web("// ```\n // ~~~", &"cpp".to_string(), false, false), + TranslationResults::CodeChat(build_codechat_for_web( + "c_cpp", + "\n\n", + vec![ + build_codemirror_doc_block(0, 0, "", "//", "
\n
\n"), + build_codemirror_doc_block(1, 1, " ", "//", "
\n"), + ] + )) + ); + + // Test an unterminated HTML block. assert_eq!( - source_to_codechat_for_web("/* ```\n*/\n//", &"cpp".to_string(), false, false), + source_to_codechat_for_web("// \n // Test", &"cpp".to_string(), false, false), TranslationResults::CodeChat(build_codechat_for_web( "c_cpp", "\n\n", vec![ - build_codemirror_doc_block(0, 1, "", "/*", "
\n\n"),
-                    build_codemirror_doc_block(2, 2, "", "//", "\n
\n"), + build_codemirror_doc_block(0, 0, "", "//", "\n"), + build_codemirror_doc_block(1, 1, " ", "//", "

Test

\n"), ] )) ); diff --git a/server/src/webserver/vscode.rs b/server/src/webserver/vscode.rs index e3a29d75..d8fa2c14 100644 --- a/server/src/webserver/vscode.rs +++ b/server/src/webserver/vscode.rs @@ -369,7 +369,10 @@ pub async fn vscode_ide_websocket( } }; - // Process the file contents. Since VSCode doesn't have a PDF viewer, determine if this is a PDF file. (TODO: look at the magic number also -- "%PDF"). + // Process the file contents. Since VSCode + // doesn't have a PDF viewer, determine if this + // is a PDF file. (TODO: look at the magic + // number also -- "%PDF"). let use_pdf_js = http_request.file_path.extension() == Some(OsStr::new("pdf")); let (simple_http_response, option_update) = match file_contents_option { Some(file_contents) => @@ -525,6 +528,9 @@ pub async fn vscode_ide_websocket( // Open a web browser when requested. EditorMessageContents::OpenUrl(url) => { + // This doesn't work in Codespaces. TODO: send + // this back to the VSCode window, then call + // `vscode.env.openExternal(vscode.Uri.parse(url))`. if let Err(err) = open::that_detached(&url) { let msg = format!("Unable to open web browser to URL {url}: {err}"); error!("{msg}"); @@ -592,7 +598,9 @@ pub async fn vscode_ide_websocket( match file_path.to_str() { None => Err("Unable to convert path to string.".to_string()), Some(file_path_string) => { - // Use a [binary file sniffer](#binary-file-sniffer) to determine if the file is text or binary. + // Use a [binary file + // sniffer](#binary-file-sniffer) to + // determine if the file is text or binary. let is_text = if let Ok(mut fc) = File::open(&file_path).await { try_read_as_text(&mut fc).await.is_some() } else {