Skip to content

Commit 42a0bce

Browse files
committed
Fix: issues found by Claude.
1 parent e54fab4 commit 42a0bce

30 files changed

Lines changed: 463 additions & 353 deletions

CHANGELOG.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,30 @@ Changelog
2222
[Github master](https://github.com/bjones1/CodeChat_Editor)
2323
-----------------------------------------------------------
2424

25-
* No changes.
25+
* Claude code reviews revealed the following issues, which were fixed manually:
26+
* Fix multi-byte Unicode encoding bug.
27+
* Fix incorrect websocket shutdown sequence.
28+
* On websocket disconnect and reconnect, correctly retain timeouts for
29+
responses.
30+
* Change websocket response timeout to a reasonable value.
31+
* Provide better error reporting when `hashLocations.json` file isn't found.
32+
* Improve encoder performance.
33+
* Correct bug in diff computation.
34+
* Correctly handle CRLFs in files that begin with a LF.
35+
* Fix several XSS vulnerabilities.
36+
* Remove redundant reference counting on shared state.
37+
* Avoid panics when validating passwords and when converting paths to strings.
38+
* Fix bugs in nested comment parser.
39+
* Improve CLI interface with better userid/password parsing, error reporting,
40+
and ipv6 support.
41+
* Include Windows drive letter Z when looking for available drives.
42+
* Use block comment delimiter found in code, not a hard-coded C-only
43+
delimiter.
44+
* Correct many errors in the grammar for supported languages.
45+
* Add lexer support for shell scripts, Swift, TOML, and Verilog, and VHDL.
46+
* Ensure math is re-typeset after saving the document.
47+
* Delay math un-typesetting until all typesetting is complete.
48+
* Improve error reporting in VSCode extension.
2649

2750
Version 0.1.52 -- 2026-Apr-09
2851
-----------------------------

builder/src/main.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ fn quick_copy_dir<P: AsRef<Path>>(src: P, dest: P, files: Option<P>) -> io::Resu
249249
// Per
250250
// [these docs](https://learn.microsoft.com/en-us/troubleshoot/windows-server/backup-and-storage/return-codes-used-robocopy-utility),
251251
// check the return code.
252-
if cfg!(windows) && exit_code >= 8 || !cfg!(windows) && exit_code != 0 {
252+
if (cfg!(windows) && exit_code >= 8) || (!cfg!(windows) && exit_code != 0) {
253253
Err(io::Error::other(format!(
254254
"Copy process return code {exit_code} indicates failure."
255255
)))
@@ -271,6 +271,8 @@ fn remove_dir_all_if_exists<P: AsRef<Path> + std::fmt::Display>(path: P) -> io::
271271
Ok(())
272272
}
273273

274+
/// Search and replace a file using the regex. It's currently only used to
275+
/// update the version of a file; it does only one replacement.
274276
fn search_and_replace_file<
275277
P: AsRef<Path> + std::fmt::Display,
276278
S1: AsRef<str> + std::fmt::Display,
@@ -283,6 +285,8 @@ fn search_and_replace_file<
283285
let file_contents = fs::read_to_string(&path)?;
284286
let re = Regex::new(search_regex.as_ref())
285287
.map_err(|err| io::Error::other(format!("Error in search regex {search_regex}: {err}")))?;
288+
// Note that this does only one replacement -- there should be exactly one
289+
// version number to replace in a file.
286290
let file_contents_replaced = re.replace(&file_contents, replace_string.as_ref());
287291
assert_ne!(
288292
file_contents, file_contents_replaced,
@@ -413,7 +417,7 @@ fn run_install(dev: bool) -> io::Result<()> {
413417
cargo binstall cargo-outdated --no-confirm;
414418
info "cargo binstall cargo-sort";
415419
cargo binstall cargo-sort --no-confirm;
416-
info "cargo binstall cargo-audio";
420+
info "cargo binstall cargo-audit";
417421
cargo binstall cargo-audit --no-confirm;
418422
)?;
419423
}
@@ -427,7 +431,7 @@ fn run_update() -> io::Result<()> {
427431
run_cmd!(
428432
info "Builder: cargo update";
429433
cargo update --manifest-path=$BUILDER_PATH/Cargo.toml;
430-
info "VSCoe extension: cargo update";
434+
info "VSCode extension: cargo update";
431435
cargo update --manifest-path=$VSCODE_PATH/Cargo.toml;
432436
info "test_utils: cargo update"
433437
cargo update --manifest-path=$TEST_UTILS_PATH/Cargo.toml;
@@ -478,7 +482,7 @@ fn run_format_and_lint(check_only: bool) -> io::Result<()> {
478482
cargo audit --file=$BUILDER_PATH/Cargo.lock --no-fetch;
479483
info "VSCode extension: cargo audit";
480484
cargo audit --file=$VSCODE_PATH/Cargo.lock --no-fetch;
481-
info "test_utils: cargo clippy and fmt"
485+
info "test_utils: cargo audit"
482486
cargo audit --file=$TEST_UTILS_PATH/Cargo.lock --no-fetch;
483487

484488
info "cargo sort";
@@ -578,7 +582,7 @@ fn run_client_build(
578582
true,
579583
)?;
580584

581-
// \<a id="#pdf.js>The PDF viewer for use with VSCode. Built it separately,
585+
// \<a id="#pdf.js>The PDF viewer for use with VSCode. Build it separately,
582586
// since it's loaded apart from the rest of the Client.
583587
run_script(
584588
&esbuild,

client/package.json5

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
'@codemirror/lang-sql': '^6.10.0',
6161
'@codemirror/lang-xml': '^6.1.0',
6262
'@codemirror/lang-yaml': '^6.1.3',
63+
'@codemirror/language': '^6.12.3',
64+
'@codemirror/legacy-modes': '^6.5.2',
6365
'@codemirror/state': '^6.6.0',
6466
'@codemirror/view': '6.38.8',
6567
'@hpcc-js/wasm-graphviz': '^1.21.2',
@@ -79,20 +81,20 @@
7981
'@types/mocha': '^10.0.10',
8082
'@types/node': '^24.12.2',
8183
'@types/toastify-js': '^1.12.4',
82-
'@typescript-eslint/eslint-plugin': '^8.58.1',
83-
'@typescript-eslint/parser': '^8.58.1',
84+
'@typescript-eslint/eslint-plugin': '^8.58.2',
85+
'@typescript-eslint/parser': '^8.58.2',
8486
chai: '^6.2.2',
8587
esbuild: '^0.28.0',
8688
eslint: '^10.2.0',
8789
'eslint-config-prettier': '^10.1.8',
8890
'eslint-plugin-import': '^2.32.0',
8991
'eslint-plugin-prettier': '^5.5.5',
90-
globals: '^17.4.0',
92+
globals: '^17.5.0',
9193
mocha: '^11.7.5',
92-
'npm-check-updates': '^20.0.0',
93-
prettier: '^3.8.1',
94+
'npm-check-updates': '^20.0.2',
95+
prettier: '^3.8.2',
9496
typescript: '^6.0.2',
95-
'typescript-eslint': '^8.58.1',
97+
'typescript-eslint': '^8.58.2',
9698
},
9799
scripts: {
98100
test: 'echo "Error: no test specified" && exit 1',

client/src/CodeChatEditor-test.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import "mocha/mocha.js";
2727
import "mocha/mocha.css";
2828
import { EditorView } from "@codemirror/view";
2929
import { ChangeSpec, EditorState, EditorSelection } from "@codemirror/state";
30-
import { CodeMirror, CodeMirrorDocBlockTuple } from "./shared_types.mjs";
30+
import { CodeMirror, CodeMirrorDocBlockTuple } from "./shared.mjs";
3131
import {
3232
DocBlockPlugin,
3333
CodeMirror_JSON_fields,

client/src/CodeChatEditor.mts

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ import {
7171
CodeMirror,
7272
autosave_timeout_ms,
7373
rand,
74-
} from "./shared_types.mjs";
74+
} from "./shared.mjs";
7575
import { show_toast } from "./show_toast.mjs";
7676

7777
// ### CSS
@@ -257,10 +257,10 @@ const _open_lp = async (
257257
// Get the mode from the page's query parameters. Default to edit using
258258
// the
259259
// [nullish coalescing operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator).
260-
// TODO: this isn't typesafe, since the `mode` might not be a key of
261-
// `EditorMode`.
262-
/// @ts-expect-error("See above.")
263-
const _editorMode = EditorMode[urlParams.get("mode") ?? "edit"];
260+
const mode = urlParams.get("mode") ?? EditorMode.edit;
261+
const _editorMode = Object.values(EditorMode).includes(mode)
262+
? mode
263+
: EditorMode.edit;
264264

265265
// Get the <code>[current_metadata](#current_metadata)</code> from the
266266
// provided `code_chat_for_web` struct and store it as a global
@@ -372,7 +372,11 @@ const _open_lp = async (
372372
}
373373
};
374374

375-
const save_lp = async (is_dirty: boolean) => {
375+
const save_lp = async (
376+
// Avoid relying on the global `is_dirty`, which may change during an
377+
// `await`.
378+
is_dirty_now: boolean,
379+
) => {
376380
const update: UpdateMessageContents = {
377381
// The Framework will fill in this value.
378382
file_path: "",
@@ -385,7 +389,7 @@ const save_lp = async (is_dirty: boolean) => {
385389
}
386390

387391
// Add the contents only if the document is dirty.
388-
if (is_dirty) {
392+
if (is_dirty_now) {
389393
/// @ts-expect-error("Declare here; it will be completed later.")
390394
let code_mirror_diffable: CodeMirrorDiffable = {};
391395
if (is_doc_only()) {
@@ -394,20 +398,25 @@ const save_lp = async (is_dirty: boolean) => {
394398
"CodeChat-body",
395399
) as HTMLDivElement;
396400
mathJaxUnTypeset(codechat_body);
397-
// To save a document only, simply get the HTML from the only Tiny
398-
// MCE div. Update the `doc_contents` to stay in sync with the
399-
// Server.
400-
doc_content = tinymce.activeEditor!.save();
401-
(
402-
code_mirror_diffable as {
403-
Plain: CodeMirror;
404-
}
405-
).Plain = {
406-
doc: doc_content,
407-
doc_blocks: [],
408-
};
409-
// Retypeset all math after saving the document.
410-
await mathJaxTypeset(codechat_body);
401+
// Use a try/finally to ensure that the document is retypeset even
402+
// if errors occur.
403+
try {
404+
// To save a document only, simply get the HTML from the only
405+
// Tiny MCE div. Update the `doc_contents` to stay in sync with
406+
// the Server.
407+
doc_content = tinymce.activeEditor!.save();
408+
(
409+
code_mirror_diffable as {
410+
Plain: CodeMirror;
411+
}
412+
).Plain = {
413+
doc: doc_content,
414+
doc_blocks: [],
415+
};
416+
} finally {
417+
// Retypeset all math after saving the document.
418+
await mathJaxTypeset(codechat_body);
419+
}
411420
} else {
412421
code_mirror_diffable = CodeMirror_save();
413422
assert("Plain" in code_mirror_diffable);
@@ -518,15 +527,6 @@ export const restoreSelection = ({
518527
}
519528
};
520529

521-
// Per
522-
// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/platform#examples),
523-
// here's the least bad way to choose between the control key and the command
524-
// key.
525-
const _os_is_osx =
526-
navigator.platform.indexOf("Mac") === 0 || navigator.platform === "iPhone"
527-
? true
528-
: false;
529-
530530
// Save CodeChat Editor contents.
531531
const on_save = async (only_if_dirty: boolean = false) => {
532532
if (only_if_dirty && !is_dirty) {

client/src/CodeChatEditorFramework.mts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
// `CodeChatEditorFramework.mts` -- the CodeChat Editor Client Framework
1818
// =====================================================================
1919
//
20-
// This maintains a websocket connection between the CodeChat Editor Server. The
20+
// This maintains a websocket connection with the CodeChat Editor Server. The
2121
// accompanying HTML is a full-screen iframe, allowing the Framework to change
2222
// or update the webpage in response to messages received from the websocket, or
2323
// to report navigation events to as a websocket message when the iframe's
@@ -40,7 +40,7 @@ import {
4040
KeysOfRustEnum,
4141
MessageResult,
4242
UpdateMessageContents,
43-
} from "./shared_types.mjs";
43+
} from "./shared.mjs";
4444
import {
4545
console_log,
4646
on_error,
@@ -207,6 +207,7 @@ class WebSocketComm {
207207
contents,
208208
current_update.is_re_translation,
209209
current_update.cursor_position,
210+
current_update.scroll_position,
210211
);
211212
} else {
212213
// If the page is still loading, wait until the
@@ -285,8 +286,7 @@ class WebSocketComm {
285286
// `pending_messages`.
286287
const pending_message = this.pending_messages[id];
287288
if (pending_message !== undefined) {
288-
const { timer_id, callback } =
289-
this.pending_messages[id];
289+
const { timer_id, callback } = pending_message;
290290
clearTimeout(timer_id);
291291
callback();
292292
delete this.pending_messages[id];
@@ -523,7 +523,7 @@ export const format_struct = (complex_data_structure: any): string =>
523523
/*eslint-disable-next-line @typescript-eslint/no-explicit-any */
524524
const report_error = (text: string, ...objs: any) => {
525525
console.error(text);
526-
if (objs !== undefined) {
526+
if (objs.length > 0) {
527527
console.log(...objs);
528528
}
529529
show_toast(text);

0 commit comments

Comments
 (0)