From dc7da26f6df2e3290d0afc08816976449008fc54 Mon Sep 17 00:00:00 2001 From: "Bryan A. Jones" Date: Fri, 10 Apr 2026 10:51:52 +0500 Subject: [PATCH 1/9] Add: invoke cargo/pnpm audit during format/lint build command. --- builder/src/main.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/builder/src/main.rs b/builder/src/main.rs index 8316a12..4b6080c 100644 --- a/builder/src/main.rs +++ b/builder/src/main.rs @@ -413,6 +413,8 @@ fn run_install(dev: bool) -> io::Result<()> { cargo binstall cargo-outdated --no-confirm; info "cargo binstall cargo-sort"; cargo binstall cargo-sort --no-confirm; + info "cargo binstall cargo-audio"; + cargo binstall cargo-audit --no-confirm; )?; } Ok(()) @@ -469,6 +471,16 @@ fn run_format_and_lint(check_only: bool) -> io::Result<()> { info "test_utils: cargo clippy and fmt" cargo clippy --all-targets --all-features --tests --manifest-path=$TEST_UTILS_PATH/Cargo.toml -- $clippy_check_only; cargo fmt --all $check --manifest-path=$TEST_UTILS_PATH/Cargo.toml; + + info "cargo audit"; + cargo audit; + info "Builder: cargo audit"; + cargo audit --file=$BUILDER_PATH/Cargo.lock --no-fetch; + info "VSCode extension: cargo audit"; + cargo audit --file=$VSCODE_PATH/Cargo.lock --no-fetch; + info "test_utils: cargo clippy and fmt" + cargo audit --file=$TEST_UTILS_PATH/Cargo.lock --no-fetch; + info "cargo sort"; cargo sort $check; cd $BUILDER_PATH; @@ -487,7 +499,9 @@ fn run_format_and_lint(check_only: bool) -> io::Result<()> { eslint_args.push(eslint_check) } run_script("npx", &eslint_args, CLIENT_PATH, true)?; - run_script("npx", &eslint_args, VSCODE_PATH, true) + run_script("npx", &eslint_args, VSCODE_PATH, true)?; + run_script("pnpm", &["audit", "--prod"], CLIENT_PATH, false)?; + run_script("pnpm", &["audit", "--prod"], VSCODE_PATH, false) } fn run_test() -> io::Result<()> { From 044fedfd4f308bfc282402a121e9d3febad6a587 Mon Sep 17 00:00:00 2001 From: "Bryan A. Jones" Date: Fri, 10 Apr 2026 16:38:09 +0500 Subject: [PATCH 2/9] Fix: issues found by Claude code reviews. --- server/src/ide/filewatcher.rs | 39 ++++++----- server/src/ide/vscode.rs | 7 +- server/src/translation.rs | 2 + server/src/webserver.rs | 127 ++++++++++++++++------------------ 4 files changed, 87 insertions(+), 88 deletions(-) diff --git a/server/src/ide/filewatcher.rs b/server/src/ide/filewatcher.rs index 93b2829..79d00da 100644 --- a/server/src/ide/filewatcher.rs +++ b/server/src/ide/filewatcher.rs @@ -67,7 +67,7 @@ use crate::{ translation::{create_translation_queues, translation_task}, webserver::{ EditorMessage, EditorMessageContents, RESERVED_MESSAGE_ID, UpdateMessageContents, - client_websocket, get_client_framework, html_not_found, html_wrapper, path_display, + client_websocket, get_client_framework, html_wrapper, http_not_found, path_display, send_response, }, }; @@ -135,8 +135,8 @@ async fn filewatcher_browser_endpoint( let canon_path = match Path::new(&fixed_path).canonicalize() { Ok(p) => p, Err(err) => { - return Ok(html_not_found(&format!( - "

The requested path {fixed_path} is not valid: {err}.

" + return Ok(http_not_found(&format!( + "The requested path {fixed_path} is not valid: {err}." ))); } }; @@ -150,8 +150,8 @@ async fn filewatcher_browser_endpoint( // It's not a directory or a file...we give up. For simplicity, don't handle // symbolic links. - Ok(html_not_found(&format!( - "

The requested path {} is not a directory or a file.

", + Ok(http_not_found(&format!( + "The requested path {} is not a directory or a file.", path_display(&canon_path) ))) } @@ -172,7 +172,7 @@ async fn dir_listing(web_path: &str, dir_path: &Path) -> HttpResponse { let mut drive_html = String::new(); let logical_drives = match get_logical_drive() { Ok(v) => v, - Err(err) => return html_not_found(&format!("Unable to list drive letters: {err}.")), + Err(err) => return http_not_found(&format!("Unable to list drive letters: {err}.")), }; for drive_letter in logical_drives { drive_html.push_str(&format!( @@ -196,8 +196,8 @@ async fn dir_listing(web_path: &str, dir_path: &Path) -> HttpResponse { let mut unwrapped_read_dir = match fs::read_dir(dir_path).await { Ok(p) => p, Err(err) => { - return html_not_found(&format!( - "

Unable to list the directory {}: {err}/

", + return http_not_found(&format!( + "Unable to list the directory {}: {err}", path_display(dir_path) )); } @@ -213,8 +213,8 @@ async fn dir_listing(web_path: &str, dir_path: &Path) -> HttpResponse { let file_type = match dir_entry.file_type().await { Ok(x) => x, Err(err) => { - return html_not_found(&format!( - "

Unable to determine the type of {}: {err}.", + return http_not_found(&format!( + "Unable to determine the type of {}: {err}.", path_display(&dir_entry.path()), )); } @@ -230,7 +230,7 @@ async fn dir_listing(web_path: &str, dir_path: &Path) -> HttpResponse { } } Err(err) => { - return html_not_found(&format!("

Unable to read file in directory: {err}.")); + return http_not_found(&format!("Unable to read file in directory: {err}.")); } }; } @@ -256,8 +256,8 @@ async fn dir_listing(web_path: &str, dir_path: &Path) -> HttpResponse { let dir_name = match dir.file_name().into_string() { Ok(v) => v, Err(err) => { - return html_not_found(&format!( - "

Unable to decode directory name '{err:?}' as UTF-8." + return http_not_found(&format!( + "Unable to decode directory name '{err:?}' as UTF-8." )); } }; @@ -273,9 +273,7 @@ async fn dir_listing(web_path: &str, dir_path: &Path) -> HttpResponse { let file_name = match file.file_name().into_string() { Ok(v) => v, Err(err) => { - return html_not_found( - &format!("

Unable to decode file name {err:?} as UTF-8.",), - ); + return http_not_found(&format!("Unable to decode file name {err:?} as UTF-8.",)); } }; let encoded_file = urlencoding::encode(&file_name); @@ -305,10 +303,13 @@ async fn dir_listing(web_path: &str, dir_path: &Path) -> HttpResponse { .body(html_wrapper(&body)) } -/// Calls the [GetLogicalDrives](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getlogicaldrives) Windows API function -/// and returns a `Vector` of drive letters. +/// Calls the +/// [GetLogicalDrives](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getlogicaldrives) +/// Windows API function and returns a `Vector` of drive letters. /// -/// Copied almost verbatim from the [win_partitions crate](https://docs.rs/crate/win_partitions/0.3.0/source/src/win_api.rs#144) when compilation errors broke the crate. +/// Copied almost verbatim from the +/// [win\_partitions crate](https://docs.rs/crate/win_partitions/0.3.0/source/src/win_api.rs#144) +/// when compilation errors broke the crate. #[cfg(target_os = "windows")] pub fn get_logical_drive() -> Result, std::io::Error> { let bitmask = unsafe { GetLogicalDrives() }; diff --git a/server/src/ide/vscode.rs b/server/src/ide/vscode.rs index 94d8883..5c431e5 100644 --- a/server/src/ide/vscode.rs +++ b/server/src/ide/vscode.rs @@ -34,6 +34,7 @@ use actix_web::{ error::{Error, ErrorBadRequest}, get, web, }; +use htmlize::escape_text; use indoc::formatdoc; use log::{debug, error}; @@ -46,8 +47,8 @@ use crate::{ }, webserver::{ EditorMessage, EditorMessageContents, IdeType, RESERVED_MESSAGE_ID, ResultErrTypes, - ResultOkTypes, WebAppState, client_websocket, escape_html, filesystem_endpoint, - get_client_framework, get_server_url, html_wrapper, send_response, + ResultOkTypes, WebAppState, client_websocket, filesystem_endpoint, get_client_framework, + get_server_url, html_wrapper, send_response, }, }; @@ -268,7 +269,7 @@ pub async fn vscode_client_framework(connection_id: web::Path) -> HttpRe Ok(web_page) => web_page, Err(html_string) => { error!("{html_string}"); - html_wrapper(&escape_html(&html_string)) + html_wrapper(&escape_text(&html_string)) } }, ) diff --git a/server/src/translation.rs b/server/src/translation.rs index 141d822..01c29e6 100644 --- a/server/src/translation.rs +++ b/server/src/translation.rs @@ -344,6 +344,7 @@ pub fn create_translation_queues( WebsocketQueues { from_websocket_tx: from_ide_tx, to_websocket_rx: to_ide_rx, + pending_messages: HashMap::new(), }, ) .is_none() @@ -360,6 +361,7 @@ pub fn create_translation_queues( WebsocketQueues { from_websocket_tx: from_client_tx, to_websocket_rx: to_client_rx, + pending_messages: HashMap::new(), }, ) .is_none() diff --git a/server/src/webserver.rs b/server/src/webserver.rs index 145172c..682e2a9 100644 --- a/server/src/webserver.rs +++ b/server/src/webserver.rs @@ -25,6 +25,7 @@ pub mod tests; // // ### Standard library use std::{ + borrow::Cow, collections::{HashMap, HashSet}, env, fs, io, net::SocketAddr, @@ -51,6 +52,7 @@ use actix_ws::AggregatedMessage; use bytes::Bytes; use dunce::simplified; use futures_util::StreamExt; +use htmlize::{escape_attribute, escape_text}; use indoc::{concatdoc, formatdoc}; use lazy_static::lazy_static; use log::{LevelFilter, error, info, warn}; @@ -104,6 +106,7 @@ use crate::{ pub struct WebsocketQueues { pub from_websocket_tx: Sender, pub to_websocket_rx: Receiver, + pub pending_messages: HashMap>, } #[derive(Debug)] @@ -327,7 +330,7 @@ pub enum IdeType { /// should be hosted in an external browser. VSCode(bool), /// Another option -- temporary -- to allow for future expansion. - DeleteMe, + Other, } /// Contents of the `Update` message. @@ -335,7 +338,7 @@ pub enum IdeType { #[ts(export, optional_fields)] pub struct UpdateMessageContents { /// The filesystem path to this file. This is only used by the IDE to - /// determine which file to apply Update contents to. The Client stores then + /// determine which file to apply Update contents to. The Client stores this /// then sends it back to the IDE in `Update` messages. This helps deal with /// transition times when the IDE and Client have different files loaded, /// guaranteeing to updates are still applied to the correct file. @@ -367,15 +370,15 @@ pub struct AppState { /// The number of the next connection ID to assign for the filewatcher. pub filewatcher_next_connection_id: Mutex, /// The port this server listens on. - pub port: Arc>, + pub port: Mutex, /// For each connection ID, store a queue tx for the HTTP server to send /// requests to the processing task for that ID. - pub processing_task_queue_tx: Arc>>>, + pub processing_task_queue_tx: Mutex>>, /// For each connection ID, store the queues for the IDE and Client. pub ide_queues: Arc>>, pub client_queues: Arc>>, /// Connection IDs that are currently in use. - pub connection_id: Arc>>, + pub connection_id: Mutex>, /// The auth credentials if authentication is used. credentials: Option, } @@ -424,7 +427,7 @@ macro_rules! queue_send_func { pub const REPLY_TIMEOUT_MS: Duration = if cfg!(test) { Duration::from_millis(500) } else { - Duration::from_millis(1500000) + Duration::from_millis(15000) }; /// The time to wait for a pong from the websocket in response to a ping sent by @@ -501,13 +504,18 @@ lazy_static! { #[cfg(debug_assertions)] hl.push("server"); hl.push("hashLocations.json"); - let json = fs::read_to_string(hl.clone()).unwrap_or_else(|_| format!(r#"{{"error": "Unable to read {:#?}"}}"#, hl.to_string_lossy())); - let hmm: HashMap = serde_json::from_str(&json).unwrap_or_else(|_| HashMap::new()); + let json = fs::read_to_string(hl.clone()).unwrap_or_else( + |err| panic!("Error: Unable to read {:#?}: {err}", hl.to_string_lossy()) + ); + let hmm: HashMap = + serde_json::from_str(&json).expect( + &format!("Unable to parse JSON in {:#?}", hl.to_string_lossy()) + ); hmm }; - static ref CODECHAT_EDITOR_FRAMEWORK_JS: String = BUNDLED_FILES_MAP.get("CodeChatEditorFramework.js").cloned().unwrap_or("Not found".to_string()); - static ref CODECHAT_EDITOR_PROJECT_CSS: String = BUNDLED_FILES_MAP.get("CodeChatEditorProject.css").cloned().unwrap_or("Not found".to_string()); + static ref CODECHAT_EDITOR_FRAMEWORK_JS: String = BUNDLED_FILES_MAP.get("CodeChatEditorFramework.js").cloned().expect("Unable to find framework JS in bundled files map."); + static ref CODECHAT_EDITOR_PROJECT_CSS: String = BUNDLED_FILES_MAP.get("CodeChatEditorProject.css").cloned().expect("Unable to find project CSS in bundled files map."); } // Define the location of the root path, which contains `static/`, `log4rs.yml`, @@ -524,8 +532,10 @@ pub fn set_root_path( let exe_dir = if let Some(ed) = extension_base_path { ed } else { - exe_path = env::current_exe().unwrap(); - exe_path.parent().unwrap() + exe_path = env::current_exe().expect("Unable to determine path to current executable."); + exe_path + .parent() + .expect("Unable to find directory name containing the current executable.") }; #[cfg(not(any(test, debug_assertions)))] let root_path = PathBuf::from(exe_dir); @@ -664,12 +674,14 @@ pub async fn filesystem_endpoint( // it here. #[cfg(not(target_os = "windows"))] let fixed_file_path = format!("/{request_file_path}"); + // TODO: security: ensure the resulting path is within the current project / + // some expected directory. let file_path = match try_canonicalize(&fixed_file_path) { Ok(v) => v, Err(err) => { let msg = format!("Error: unable to convert path {request_file_path}: {err}."); error!("{msg}"); - return html_not_found(&msg); + return http_not_found(&msg); } }; @@ -686,8 +698,8 @@ pub async fn filesystem_endpoint( .is_ok_and(|query| query.get("raw").is_some()); let is_test_mode = get_test_mode(req); let flags = if is_toc { - // Both flags should never be set. - assert!(!is_raw); + // This ignores the raw flag if it's set; since this makes not sense, + // this is ignored. ProcessingTaskHttpRequestFlags::Toc } else if is_raw { ProcessingTaskHttpRequestFlags::Raw @@ -708,7 +720,7 @@ pub async fn filesystem_endpoint( &connection_id ); error!("{msg}"); - return html_not_found(&msg); + return http_not_found(&msg); }; processing_tx.clone() }; @@ -726,7 +738,7 @@ pub async fn filesystem_endpoint( { let msg = format!("Error: unable to enqueue: {err}."); error!("{msg}"); - return html_not_found(&msg); + return http_not_found(&msg); } // Return the response provided by the processing task. @@ -735,7 +747,7 @@ pub async fn filesystem_endpoint( SimpleHttpResponse::Ok(body) => HttpResponse::Ok() .content_type(ContentType::html()) .body(body), - SimpleHttpResponse::Err(body) => html_not_found(&format!("{body}")), + SimpleHttpResponse::Err(body) => http_not_found(&format!("{body}")), SimpleHttpResponse::Raw(body, content_type) => { HttpResponse::Ok().content_type(content_type).body(body) } @@ -749,11 +761,11 @@ pub async fn filesystem_endpoint( } v.into_response(req) } - Err(err) => html_not_found(&format!("

Error opening file {path:?}: {err}.",)), + Err(err) => http_not_found(&format!("Error opening file {path:?}: {err}.",)), } } }, - Err(err) => html_not_found(&format!("Error: {err}")), + Err(err) => http_not_found(&format!("Error: {err}")), } } @@ -808,7 +820,7 @@ pub async fn file_to_response( None, ); }; - let name = escape_html(&file_name.to_string_lossy()); + let name = escape_text(file_name.to_string_lossy()); // Get the locations for bundled files. let js_test_suffix = if http_request.is_test_mode { @@ -826,7 +838,7 @@ pub async fn file_to_response( ); }; let codechat_editor_css_name = format!("CodeChatEditor{js_test_suffix}.css"); - let Some(codehat_editor_css) = BUNDLED_FILES_MAP.get(&codechat_editor_css_name) else { + let Some(codechat_editor_css) = BUNDLED_FILES_MAP.get(&codechat_editor_css_name) else { return ( SimpleHttpResponse::Err(SimpleHttpResponseError::BundledFileNotFound( codechat_editor_css_name, @@ -876,7 +888,7 @@ pub async fn file_to_response( ( format!( r#"

"#, - path_to_toc.unwrap().to_slash_lossy() + escape_attribute(path_to_toc.unwrap().to_slash_lossy()) ), format!( r#""#, @@ -910,11 +922,12 @@ pub async fn file_to_response( // as the query parameter. format!( r#""#, - http_request.url + escape_attribute(&http_request.url) ) } else { format!( - r#""# + r#""#, + escape_attribute(file_name) ) }, ), @@ -1050,7 +1063,7 @@ fn make_simple_viewer(http_request: &ProcessingTaskHttpRequest, html: &str) -> S file_path.to_path_buf(), )); }; - let file_name = escape_html(file_name); + let file_name = escape_text(file_name); let Some(path_to_toc) = find_path_to_toc(file_path) else { return SimpleHttpResponse::Err(SimpleHttpResponseError::PathNotProject( @@ -1062,7 +1075,7 @@ fn make_simple_viewer(http_request: &ProcessingTaskHttpRequest, html: &str) -> S path_to_toc.to_path_buf(), )); }; - let path_to_toc = escape_html(path_to_toc); + let path_to_toc = escape_text(path_to_toc); SimpleHttpResponse::Ok( // The JavaScript is a stripped-down version of @@ -1136,18 +1149,19 @@ pub fn client_websocket( aggregated_msg_stream = aggregated_msg_stream.max_continuation_size(10_000_000); // Transfer the queues from the global state to this task. - let (from_websocket_tx, mut to_websocket_rx) = + let (from_websocket_tx, mut to_websocket_rx, mut pending_messages) = match websocket_queues.lock().unwrap().remove(&connection_id) { - Some(queues) => (queues.from_websocket_tx.clone(), queues.to_websocket_rx), + Some(queues) => ( + queues.from_websocket_tx.clone(), + queues.to_websocket_rx, + queues.pending_messages, + ), None => { error!("No websocket queues for connection id {connection_id}."); return; } }; - // Keep track of pending messages. - let mut pending_messages: HashMap> = HashMap::new(); - // Shutdown may occur in a controlled process or an immediate websocket // close. If the Client needs to close, it can simply close its // websocket, since the IDE maintains all state (case 2). However, if @@ -1353,18 +1367,19 @@ pub fn client_websocket( while let Some(m) = to_websocket_rx.recv().await { warn!("Dropped queued message {m:?}"); } - to_websocket_rx.close(); // Stop all timers. for (_id, join_handle) in pending_messages.drain() { join_handle.abort(); } } else { + // Don't stop timers; the re-connection may handle them. info!("Websocket re-enqueued."); websocket_queues.lock().unwrap().insert( connection_id.to_string(), WebsocketQueues { from_websocket_tx, to_websocket_rx, + pending_messages, }, ); } @@ -1458,13 +1473,9 @@ async fn basic_validator( credentials: BasicAuth, ) -> Result { // Get the provided credentials. - let expected_credentials = &req - .app_data::() - .unwrap() - .credentials - .as_ref() - .unwrap(); - if credentials.user_id() == expected_credentials.username + if let Some(app_state) = &req.app_data::() + && let Some(expected_credentials) = app_state.credentials.as_ref() + && credentials.user_id() == expected_credentials.username && credentials.password() == Some(&expected_credentials.password) { Ok(req) @@ -1500,11 +1511,11 @@ pub fn make_app_data(credentials: Option) -> WebAppState { server_handle: Mutex::new(None), filewatcher_next_connection_id: Mutex::new(0), // Use a dummy value until the server binds to a port. - port: Arc::new(Mutex::new(0)), - processing_task_queue_tx: Arc::new(Mutex::new(HashMap::new())), + port: Mutex::new(0), + processing_task_queue_tx: Mutex::new(HashMap::new()), ide_queues: Arc::new(Mutex::new(HashMap::new())), client_queues: Arc::new(Mutex::new(HashMap::new())), - connection_id: Arc::new(Mutex::new(HashSet::new())), + connection_id: Mutex::new(HashSet::new()), credentials, }) } @@ -1676,8 +1687,7 @@ pub fn try_canonicalize(file_path: &str) -> Result, file_path: &Path) -> String { // First, convert the path to use forward slashes. let pathname = simplified(file_path) - .to_slash() - .unwrap() + .to_slash_lossy() // The convert each part of the path to a URL-encoded string. (This // avoids encoding the slashes.) .split("/") @@ -1699,26 +1709,20 @@ pub fn path_to_url(prefix: &str, connection_id: Option<&str>, file_path: &Path) // Given a string (which is probably a pathname), drop the leading slash if it's // present. pub fn drop_leading_slash(path_: &str) -> &str { - if path_.starts_with("/") { - let mut chars = path_.chars(); - chars.next(); - chars.as_str() - } else { - path_ - } + path_.strip_prefix('/').unwrap_or(path_) } // Given a `Path`, transform it into a displayable HTML string (with any // necessary escaping). -pub fn path_display(p: &Path) -> String { - escape_html(&simplified(p).to_string_lossy()) +pub fn path_display(p: &Path) -> Cow<'_, str> { + escape_text(simplified(p).to_string_lossy()) } -// Return a Not Found (404) error with the provided HTML body. -pub fn html_not_found(msg: &str) -> HttpResponse { +// Return a Not Found (404) error with the provided text (not HTML) body. +pub fn http_not_found(msg: &str) -> HttpResponse { HttpResponse::NotFound() .content_type(ContentType::html()) - .body(html_wrapper(msg)) + .body(html_wrapper(&escape_text(msg))) } // Wrap the provided HTML body in DOCTYPE/html/head tags. @@ -1739,15 +1743,6 @@ pub fn html_wrapper(body: &str) -> String { ) } -// Given text, escape it so it formats correctly as HTML. This is a translation -// of Python's `html.escape` function. -pub fn escape_html(unsafe_text: &str) -> String { - unsafe_text - .replace('&', "&") - .replace('<', "<") - .replace('>', ">") -} - // This lists all errors produced by calling `get_server_url`. TODO: rework and // re-think the overall error framework. How should I group errors? #[derive(Debug, thiserror::Error)] From 1e513efc50e66af3876240346c2d5db6183f9ed6 Mon Sep 17 00:00:00 2001 From: "Bryan A. Jones" Date: Fri, 10 Apr 2026 16:58:19 +0500 Subject: [PATCH 3/9] Clean: reformat Markdown in files. --- builder/.gitignore | 2 +- builder/Cargo.toml | 2 +- client/eslint.config.js | 8 +-- client/readme.md | 2 +- client/src/CodeChatEditor-test.mts | 6 +-- client/src/HashReader.mts | 2 +- client/src/assert.mts | 2 +- client/src/css/CodeChatEditor.css | 12 ++--- client/src/css/CodeChatEditorProject.css | 2 +- client/src/css/themes/light.css | 2 +- client/src/global.d.ts | 5 +- client/src/graphviz-webcomponent-setup.mjs | 2 +- client/src/shared_types.mts | 2 +- .../src/third-party/wc-mermaid/developer.md | 4 +- client/src/tinymce-config.mts | 2 +- client/tsconfig.json | 6 ++- docs/design.md | 11 ++-- docs/implementation.md | 20 +++---- docs/style_guide.cpp | 30 +++++------ extensions/VSCode/.vscodeignore | 4 +- extensions/VSCode/Cargo.toml | 4 +- extensions/VSCode/README.md | 8 +-- extensions/VSCode/developer.md | 54 +++++++++---------- extensions/VSCode/eslint.config.js | 8 +-- extensions/VSCode/src/lib.rs | 6 +-- extensions/VSCode/tsconfig.json | 4 +- extensions/readme.md | 2 +- server/.cargo/config.toml | 4 +- server/dist.toml | 4 +- server/src/ide.rs | 6 +-- server/src/ide/filewatcher.rs | 10 ++-- server/src/ide/vscode.rs | 10 ++-- server/src/ide/vscode/tests.rs | 11 ++-- server/src/lexer.rs | 16 +++--- server/src/lexer/pest/c.pest | 8 +-- server/src/lexer/pest/python.pest | 10 ++-- server/src/lexer/pest/shared.pest | 10 ++-- server/src/lexer/pest_parser.rs | 10 ++-- server/src/lexer/supported_languages.rs | 10 ++-- server/src/lexer/tests.rs | 6 +-- server/src/lib.rs | 2 +- server/src/main.rs | 8 +-- server/src/processing.rs | 18 +++---- server/src/webserver.rs | 20 +++---- server/src/webserver/tests.rs | 8 +-- server/tests/cli.rs | 8 +-- test_utils/readme.md | 2 +- test_utils/src/test_macros.rs | 6 +-- test_utils/src/test_utils.rs | 8 +-- test_utils/src/testing_logger.rs | 4 +- toc.md | 10 ++-- 51 files changed, 216 insertions(+), 205 deletions(-) diff --git a/builder/.gitignore b/builder/.gitignore index 1b33dcd..2d3f357 100644 --- a/builder/.gitignore +++ b/builder/.gitignore @@ -17,7 +17,7 @@ # [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/). # # `.gitignore` -- files for Git to ignore -# ============================================================================== +# ======================================= # # Rust build output target/ diff --git a/builder/Cargo.toml b/builder/Cargo.toml index 79c2667..8662b73 100644 --- a/builder/Cargo.toml +++ b/builder/Cargo.toml @@ -17,7 +17,7 @@ # [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/). # # `Cargo.toml` -- Rust build/package management config for the builder -# ============================================================================== +# ==================================================================== [package] name = "builder" version = "0.1.0" diff --git a/client/eslint.config.js b/client/eslint.config.js index 494ef87..37e169c 100644 --- a/client/eslint.config.js +++ b/client/eslint.config.js @@ -2,8 +2,8 @@ // // This file is part of the CodeChat Editor. // -// The CodeChat Editor is free software: you can redistribute it and/or modify it -// under the terms of the GNU General Public License as published by the Free +// The CodeChat Editor is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) any // later version. // @@ -30,7 +30,9 @@ export default defineConfig( eslintPluginPrettierRecommended, defineConfig([ { - // This must be the only key in this dict to be treated as a global ignore. Only global ignores can ignore directories. See the [docs](https://eslint.org/docs/latest/use/configure/configuration-files#globally-ignoring-files-with-ignores). + // This must be the only key in this dict to be treated as a global + // ignore. Only global ignores can ignore directories. See the + // [docs](https://eslint.org/docs/latest/use/configure/configuration-files#globally-ignoring-files-with-ignores). ignores: ["src/third-party/**"], }, { diff --git a/client/readme.md b/client/readme.md index 7a30e8b..8c928fd 100644 --- a/client/readme.md +++ b/client/readme.md @@ -1,5 +1,5 @@ `readme.md` - overview of the Client -================================================================================ +==================================== Inside the client: diff --git a/client/src/CodeChatEditor-test.mts b/client/src/CodeChatEditor-test.mts index 2ae94fb..3f7346c 100644 --- a/client/src/CodeChatEditor-test.mts +++ b/client/src/CodeChatEditor-test.mts @@ -15,13 +15,13 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // // `CodeChatEditor-test.mts` -- Tests for the CodeChat Editor client -// ============================================================================= +// ================================================================= // // To run tests, add a `?test` to any web page served by the CodeChat Editor // server. // // Imports -// ----------------------------------------------------------------------------- +// ------- import { assert } from "chai"; import "mocha/mocha.js"; import "mocha/mocha.css"; @@ -44,7 +44,7 @@ import { const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)); // Tests -// ----------------------------------------------------------------------------- +// ----- // // Defining this global variable signals the // CodeChat Editor to [run tests](CodeChatEditor.mts#CodeChatEditor_test). diff --git a/client/src/HashReader.mts b/client/src/HashReader.mts index 514dc3b..b62ecf5 100644 --- a/client/src/HashReader.mts +++ b/client/src/HashReader.mts @@ -15,7 +15,7 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // // `HashReader.mts` -- post-process esbuild output -// ============================================================================= +// =============================================== // // This script reads the output produced by esbuild to determine the location of // the bundled files, which have hashes in their file names. It writes these diff --git a/client/src/assert.mts b/client/src/assert.mts index e3b74a4..f594c16 100644 --- a/client/src/assert.mts +++ b/client/src/assert.mts @@ -15,7 +15,7 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // // `assert.mts` -// ============================================================================= +// ============ // // Provide a simple `assert` function to check conditions at runtime. Using // things like [assert](https://nodejs.org/api/assert.html) causes problems -- diff --git a/client/src/css/CodeChatEditor.css b/client/src/css/CodeChatEditor.css index 842c1fd..ae923d1 100644 --- a/client/src/css/CodeChatEditor.css +++ b/client/src/css/CodeChatEditor.css @@ -17,7 +17,7 @@ [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/). `CodeChatEditor.css` -- Styles for the CodeChat Editor - ============================================================================= + ====================================================== This style sheet is used by the HTML generated by [CodeChatEditor.mts](../CodeChatEditor.mts). @@ -26,13 +26,13 @@ whether they style a code or doc block. Import a theme - ----------------------------------------------------------------------------- + -------------- Eventually, this will be a user-configurable setting. */ @import url("themes/light.css"); /* Styles for the entire page layout - ----------------------------------------------------------------------------- + --------------------------------- This is used only to store a reused variable value. See the [CSS docs](https://drafts.csswg.org/css-variables/). */ @@ -73,7 +73,7 @@ body { } } /* Misc styling - ----------------------------------------------------------------------------- + ------------ Make the filename compact. */ #CodeChat-filename p { @@ -82,7 +82,7 @@ body { } /* Doc block styling - ----------------------------------------------------------------------------- */ + ----------------- */ .CodeChat-doc { /* Use [flexbox layout](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox) @@ -130,7 +130,7 @@ body { } /* Combined code/doc block styling - ----------------------------------------------------------------------------- + ------------------------------- Remove space between a code block followed by a doc block. Doc block elements typically have top margin and/or padding that diff --git a/client/src/css/CodeChatEditorProject.css b/client/src/css/CodeChatEditorProject.css index f3cb0df..c42d02b 100644 --- a/client/src/css/CodeChatEditorProject.css +++ b/client/src/css/CodeChatEditorProject.css @@ -17,7 +17,7 @@ [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/). `CodeChatEditorProject.css` -- Styles for the CodeChat Editor for projects - ============================================================================= + ========================================================================== This is used only to store a reused variable value. See the [CSS docs](https://drafts.csswg.org/css-variables/). */ diff --git a/client/src/css/themes/light.css b/client/src/css/themes/light.css index 12e0575..4e9ddc5 100644 --- a/client/src/css/themes/light.css +++ b/client/src/css/themes/light.css @@ -17,7 +17,7 @@ [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/). `light.css` -- Styles for the light theme - ============================================================================= + ========================================= Use [CSS nesting](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting/Using_CSS_nesting) diff --git a/client/src/global.d.ts b/client/src/global.d.ts index b9f7d19..0dbec99 100644 --- a/client/src/global.d.ts +++ b/client/src/global.d.ts @@ -15,9 +15,10 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // // `global.d.ts` -- Global type definitions -// ============================================================================= +// ======================================== // -// Copied from the [TypeScript Docs](https://www.typescriptlang.org/tsconfig/#noUncheckedSideEffectImports): +// Copied from the +// [TypeScript Docs](https://www.typescriptlang.org/tsconfig/#noUncheckedSideEffectImports): // // Recognize all CSS files as module imports. declare module "*.css" {} diff --git a/client/src/graphviz-webcomponent-setup.mjs b/client/src/graphviz-webcomponent-setup.mjs index b763c6a..ca8876a 100644 --- a/client/src/graphviz-webcomponent-setup.mjs +++ b/client/src/graphviz-webcomponent-setup.mjs @@ -15,7 +15,7 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // // `graphviz-webcomponent-setup.mts` -- Configure graphviz webcomponent options -// ============================================================================= +// ============================================================================ // // Configure the Graphviz web component to load the (large) renderer only when a // Graphviz web component is found on a page. See the diff --git a/client/src/shared_types.mts b/client/src/shared_types.mts index a30afb4..1f003cb 100644 --- a/client/src/shared_types.mts +++ b/client/src/shared_types.mts @@ -15,7 +15,7 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // // `shared_types.mts` -- Shared type definitions -// ============================================================================= +// ============================================= // // The time, in ms, to wait between the last user edit and sending updated data // to the Server. diff --git a/client/src/third-party/wc-mermaid/developer.md b/client/src/third-party/wc-mermaid/developer.md index b25ea38..638c609 100644 --- a/client/src/third-party/wc-mermaid/developer.md +++ b/client/src/third-party/wc-mermaid/developer.md @@ -3,5 +3,5 @@ Mermaid support This file is based on [wc-mermaid](https://github.com/manolakis/wc-mermaid). The code here was modified to allow a dynamic import of Mermaid and updated to -support modern Mermaid. This software is licensed separately under the [Mermaid -license](LICENSE.md). \ No newline at end of file +support modern Mermaid. This software is licensed separately under the +[Mermaid license](LICENSE.md). diff --git a/client/src/tinymce-config.mts b/client/src/tinymce-config.mts index 4672316..d6c7a89 100644 --- a/client/src/tinymce-config.mts +++ b/client/src/tinymce-config.mts @@ -16,7 +16,7 @@ // // `tinymce-config.ts` -- integrate and configure the TinyMCE editor for use // with the CodeChat Editor -// ============================================================================= +// ========================================================================= // // Import TinyMCE. import { diff --git a/client/tsconfig.json b/client/tsconfig.json index 5542e6a..520b0f2 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -15,7 +15,7 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // // tsconfig.json -- TypeScript configuration -// ============================================================================= +// ========================================= { "compilerOptions": { "allowJs": true, @@ -33,7 +33,9 @@ "outDir": "out", "rootDir": "./src", "strict": true, - // Starting in TypeScript 6.0, no ambient type packages are auto-included. Add these explicitly. See the [TypeScript 5.x to 6.0 Migration Guide](https://gist.github.com/privatenumber/3d2e80da28f84ee30b77d53e1693378f#16-types-defaults-to-). + // Starting in TypeScript 6.0, no ambient type packages are + // auto-included. Add these explicitly. See the + // [TypeScript 5.x to 6.0 Migration Guide](https://gist.github.com/privatenumber/3d2e80da28f84ee30b77d53e1693378f#16-types-defaults-to-). "types": ["node", "mocha"] }, "exclude": ["node_modules", "static", "HashReader.js", "eslint.config.js"] diff --git a/docs/design.md b/docs/design.md index 798f245..173ec9f 100644 --- a/docs/design.md +++ b/docs/design.md @@ -1,8 +1,8 @@ CodeChat Editor design -================================================================================ +====================== To build from source --------------------------------------------------------------------------------- +-------------------- 1. Clone or download the repository. 2. [Install the Rust language](https://www.rust-lang.org/tools/install). I @@ -18,7 +18,7 @@ Use `./bt` tool's options update all libraries (`update`), run all tests (`test`), and more. Vision --------------------------------------------------------------------------------- +------------------------- These form a set of high-level requirements to guide the project. @@ -136,7 +136,7 @@ These form a set of high-level requirements to guide the project. * An API-only view (Doxygen/Javadoc like feature). Requirements --------------------------------------------------------------------------------- +-------------------------------------- The requirements expand on the vision by providing additional details. @@ -204,7 +204,6 @@ void foo(); ### \[Programming language support\](index.md#programming-language-support) - Initial targets come from the Stack Overflow Developer Survey 2022's section on [programming, scripting, and markup languages](https://survey.stackoverflow.co/2022/#section-most-popular-technologies-programming-scripting-and-markup-languages) and IEEE Spectrum's @@ -256,7 +255,7 @@ When a new tag is inserted, any tag-produced content should be immediately added. License --------------------------------------------------------------------------------- +------- Copyright (C) 2025 Bryan A. Jones. diff --git a/docs/implementation.md b/docs/implementation.md index 8323b35..445d777 100644 --- a/docs/implementation.md +++ b/docs/implementation.md @@ -17,7 +17,7 @@ CodeChat Editor. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/). Implementation -================================================================================ +============== ### System architecture @@ -65,7 +65,7 @@ a diagram as an overview might be helpful. Perhaps the server, client, etc. should have its of readme files providing some of this. Architecture --------------------------------------------------------------------------------- +------------------------------------------ Overall, the code is something like this: @@ -317,7 +317,7 @@ More complex IDE integration: everything that the simple IDE does, plus the ability to toggle between the IDE's editor and the CodeChat Editor. Build system --------------------------------------------------------------------------------- +------------ The app needs build support because of complexity: @@ -329,7 +329,7 @@ So, this project contains Rust code to automate this process -- see the [builder](../builder/Cargo.toml). Misc topics --------------------------------------------------------------------------------- +----------- ### CodeChat Editor Client Viewer Types @@ -359,7 +359,7 @@ closing tags are removed from the HTML. This is fixed by later HTML processing steps (currently, by TinyMCE), which properly closes tags. Future work --------------------------------------------------------------------------------- +----------- ### Table of contents @@ -422,7 +422,7 @@ with descriptions of each setting. * Substitutions Core development priorities --------------------------------------------------------------------------------- +------------------------------------------------------------------ 1. Bug fixes 2. Book support @@ -462,7 +462,7 @@ with descriptions of each setting. somewhat, since it wants to decode JSON into a V struct.) Organization --------------------------------------------------------------------------------- +------------ ### Client @@ -508,7 +508,7 @@ TODO: GUIs using TinyMCE. See the [how-to guide](https://www.tiny.cloud/docs/tinymce/6/dialog-components/#panel-components). Code style --------------------------------------------------------------------------------- +---------- JavaScript functions are a [disaster](https://dmitripavlutin.com/differences-between-arrow-and-regular-functions/). @@ -518,7 +518,7 @@ Other than that, follow the [MDN style guide](https://developer.mozilla.org/en-US/docs/MDN/Writing_guidelines/Writing_style_guide/Code_style_guide/JavaScript). Client modes --------------------------------------------------------------------------------- +------------ The CodeChat Editor client supports four modes: @@ -535,7 +535,7 @@ The CodeChat Editor client supports four modes: area; otherwise, it's only the main area. See: \. Misc --------------------------------------------------------------------------------- +---- Eventually, provide a read-only mode with possible auth (restrict who can view) using JWTs; see diff --git a/docs/style_guide.cpp b/docs/style_guide.cpp index 86e0912..a62b16c 100644 --- a/docs/style_guide.cpp +++ b/docs/style_guide.cpp @@ -1,5 +1,5 @@ // `style_guide.cpp` - Literate programming using the CodeChat Editor -// ============================================================================= +// ================================================================== // // This document, written as a C++ source file, primarily demonstrates the use // of the CodeChat Editor in literate programming. It should be viewed using the @@ -22,7 +22,7 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // // Introduction -// ----------------------------------------------------------------------------- +// ------------ // // This document provides a style guide for literate programming using the // CodeChat Editor. For basic use, see the [user manual](../README.md). @@ -47,7 +47,7 @@ const char* CODE_BLOCK = // [brief overview of Markdown](https://commonmark.org/help/). // // Approach -// ----------------------------------------------------------------------------- +// -------- // // Viewing a program as a document defines the heart of the literate programming // paradigm. A program/document -- constructed as a series of code blocks and @@ -74,7 +74,7 @@ const char* CODE_BLOCK = // person to review what you wrote, then implement their ideas and suggestions. // // Organization -// ----------------------------------------------------------------------------- +// ------------------------------------- // // The program should use headings to appropriately organize the contents. Near // the top of the file, include a single level-1 heading, providing the title of @@ -91,7 +91,7 @@ const char* CODE_BLOCK = // style. // // Location -// ----------------------------------------------------------------------------- +// -------- // // In general, place documentation before the corresponding code. For example: // @@ -111,7 +111,7 @@ class LedBlinker { }; // Use of mathematics -// ----------------------------------------------------------------------------- +// ------------------ // // Formulas should be placed near code that implements them, along with good // explanations of the equations used. For example: @@ -158,7 +158,7 @@ double accurate_g( } // Excellence in code -// ----------------------------------------------------------------------------- +// ------------------ // // Literate programming should be accompanied by excellence in authoring code. // Specifically: @@ -178,7 +178,7 @@ double accurate_g( // [test-driven development](https://en.wikipedia.org/wiki/Test-driven_development). // // Editor configuration -// ----------------------------------------------------------------------------- +// -------------------- // // Properly configuring the text editor used with the CodeChat Editor // significantly improves the authoring process. Recommended settings: @@ -197,7 +197,7 @@ double accurate_g( // * On a big monitor, place your IDE side by side with the CodeChat Editor. // // Common problems -// ----------------------------------------------------------------------------- +// --------------- // // * Don't drag and drop an image into the Editor – this creates a mess. // Instead, save all images to a file, then use an SVG or PNG image for @@ -230,13 +230,13 @@ double accurate_g( // C/C++. // // Example structure -// ----------------------------------------------------------------------------- +// ----------------- // // As discussed in [organization](#organization), the remainder of this document // presents the preferred use of headings to organize source code. // // Includes -// ----------------------------------------------------------------------------- +// ------------------------------ // // Include files (in Python, imports; Rust, use statements; JavaScript, // require/import, etc.) should be organized by category; for example, @@ -256,23 +256,23 @@ double accurate_g( #include // Global variables/constants -// ----------------------------------------------------------------------------- +// -------------------------- // // Use units when describing physical quantities. For example, this gives the // acceleration due to gravity in $m/s^2$. const double accel_m_s2 = 9.8067; // Macros -// ----------------------------------------------------------------------------- +// ------ #define LED1 (LATB16) // Structures/classes -// ----------------------------------------------------------------------------- +// ------------------ class BlinkLed { }; // Code -// ----------------------------------------------------------------------------- +// ---- int main(int argc, char* argv[]) { // Here's an example of commenting code out when using the CodeChat Editor: /** diff --git a/extensions/VSCode/.vscodeignore b/extensions/VSCode/.vscodeignore index 477eb8a..cd2f89a 100644 --- a/extensions/VSCode/.vscodeignore +++ b/extensions/VSCode/.vscodeignore @@ -19,8 +19,8 @@ # `vscodeignore` - Files not to package # ===================================== # -# See [Using -# .vscodeignore](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#using-.vscodeignore). +# See +# [Using .vscodeignore](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#using-.vscodeignore). # # Omit all TypeScript source. src/** diff --git a/extensions/VSCode/Cargo.toml b/extensions/VSCode/Cargo.toml index c3adc2d..8d88935 100644 --- a/extensions/VSCode/Cargo.toml +++ b/extensions/VSCode/Cargo.toml @@ -17,10 +17,10 @@ # [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/). # # `Cargo.toml` -- Rust interface for the VSCode extension -# ============================================================================== +# ======================================================= # # General package configurations -# ------------------------------------------------------------------------------ +# ------------------------------ [package] authors = ["Bryan A. Jones", "Peter Loux"] categories = ["development-tools", "text-editors"] diff --git a/extensions/VSCode/README.md b/extensions/VSCode/README.md index 91af7fb..195ac00 100644 --- a/extensions/VSCode/README.md +++ b/extensions/VSCode/README.md @@ -1,5 +1,5 @@ The CodeChat Editor extension for Visual Studio Code -================================================================================ +==================================================== This extension provides the CodeChat Editor's capabilities within the Visual Studio Code IDE. @@ -7,7 +7,7 @@ Studio Code IDE. ![Screenshot of the CodeChat Editor extension](https://github.com/bjones1/CodeChat_Editor/blob/main/extensions/VSCode/screenshot.png?raw=true) Installation --------------------------------------------------------------------------------- +------------ First, install [Visual Studio Code](https://code.visualstudio.com/). Next: @@ -17,7 +17,7 @@ First, install [Visual Studio Code](https://code.visualstudio.com/). Next: since the CodeChat Editor only provides a light theme. Running --------------------------------------------------------------------------------- +------- 1. Open a file that the CodeChat Editor [supports](https://github.com/bjones1/CodeChat_Editor/blob/main/README.md#supported-languages) @@ -36,7 +36,7 @@ Running then select Enable the CodeChat Editor). Additional documentation --------------------------------------------------------------------------------- +------------------------ See the [user manual](https://codechat-editor.onrender.com/fw/fsb/opt/render/project/src/README.md). diff --git a/extensions/VSCode/developer.md b/extensions/VSCode/developer.md index f0412d4..3eb95ea 100644 --- a/extensions/VSCode/developer.md +++ b/extensions/VSCode/developer.md @@ -6,44 +6,44 @@ From source To install from source: -* Install [npm](https://nodejs.org/en/). +* Install [npm](https://nodejs.org/en/). -* Install this extension's manifest - ([package.json](https://code.visualstudio.com/api/references/extension-manifest)): - from this directory, open a command prompt/terminal then execute:: +* Install this extension's manifest + ([package.json](https://code.visualstudio.com/api/references/extension-manifest)): + from this directory, open a command prompt/terminal then execute:: - ``` - npm install - ``` + ``` + npm install + ``` Debugging the extension ----------------------- -* From VSCode, select File | Add Folder to Workspace... then choose the folder - containing this file. -* Press ctrl+shift+B to compile the extension. -* Press F5 or click start debugging under the Debug menu. -* A new instance of VSCode will start in a special mode (Extension Development - Host) which contains the CodeChat extension. -* Open any source code, then press Ctrl+Shift+P and type "CodeChat" to run the - CodeChat extension. You will be able to see the rendered version of your - active window. +* From VSCode, select File | Add Folder to Workspace... then choose the folder + containing this file. +* Press ctrl+shift+B to compile the extension. +* Press F5 or click start debugging under the Debug menu. +* A new instance of VSCode will start in a special mode (Extension Development + Host) which contains the CodeChat extension. +* Open any source code, then press Ctrl+Shift+P and type "CodeChat" to run the + CodeChat extension. You will be able to see the rendered version of your + active window. Release procedure ----------------- -* In the Client: - * Update the version of the plugin in `package.json`. -* In the Server: - * Update the version in `cargo.toml`. -* Here: - * Update the version of the plugin in `package.json`. - * Run `cargo run -- release` on each platform, which produces a `.vsix` - file for that platform - * Run `npx vsce publish --packagePath blah`. - ([docs](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#platformspecific-extensions)) +* In the Client: + * Update the version of the plugin in `package.json`. +* In the Server: + * Update the version in `cargo.toml`. +* Here: + * Update the version of the plugin in `package.json`. + * Run `cargo run -- release` on each platform, which produces a `.vsix` file + for that platform + * Run `npx vsce publish --packagePath blah`. + ([docs](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#platformspecific-extensions)) Tests ----- -TODO: tests are missing. \ No newline at end of file +TODO: tests are missing. diff --git a/extensions/VSCode/eslint.config.js b/extensions/VSCode/eslint.config.js index c093686..a59cc0c 100644 --- a/extensions/VSCode/eslint.config.js +++ b/extensions/VSCode/eslint.config.js @@ -2,8 +2,8 @@ // // This file is part of the CodeChat Editor. // -// The CodeChat Editor is free software: you can redistribute it and/or modify it -// under the terms of the GNU General Public License as published by the Free +// The CodeChat Editor is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) any // later version. // @@ -29,7 +29,9 @@ module.exports = defineConfig( eslintPluginPrettierRecommended, defineConfig([ { - // This must be the only key in this dict to be treated as a global ignore. Only global ignores can ignore directories. See the [docs](https://eslint.org/docs/latest/use/configure/configuration-files#globally-ignoring-files-with-ignores). + // This must be the only key in this dict to be treated as a global + // ignore. Only global ignores can ignore directories. See the + // [docs](https://eslint.org/docs/latest/use/configure/configuration-files#globally-ignoring-files-with-ignores). ignores: ["src/third-party/**"], }, { diff --git a/extensions/VSCode/src/lib.rs b/extensions/VSCode/src/lib.rs index bef4767..a0108dd 100644 --- a/extensions/VSCode/src/lib.rs +++ b/extensions/VSCode/src/lib.rs @@ -15,10 +15,10 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // // `lib.rs` -- Interface to the CodeChat Editor for VSCode -// ============================================================================= +// ======================================================= // // Imports -// ----------------------------------------------------------------------------- +// ------- // // ### Standard library use std::path::PathBuf; @@ -32,7 +32,7 @@ use napi_derive::napi; use code_chat_editor::{ide, webserver}; // Code -// ----------------------------------------------------------------------------- +// ---- #[napi] pub fn init_server(extension_base_path: String) -> Result<(), Error> { webserver::init_server( diff --git a/extensions/VSCode/tsconfig.json b/extensions/VSCode/tsconfig.json index 20c3fe7..ddf87b2 100644 --- a/extensions/VSCode/tsconfig.json +++ b/extensions/VSCode/tsconfig.json @@ -25,7 +25,9 @@ "strict": true, "rootDirs": ["src", "../../client/src/*"], "rootDir": "../..", - // Starting in TypeScript 6.0, no ambient type packages are auto-included. Add these explicitly. See the [TypeScript 5.x to 6.0 Migration Guide](https://gist.github.com/privatenumber/3d2e80da28f84ee30b77d53e1693378f#16-types-defaults-to-). + // Starting in TypeScript 6.0, no ambient type packages are + // auto-included. Add these explicitly. See the + // [TypeScript 5.x to 6.0 Migration Guide](https://gist.github.com/privatenumber/3d2e80da28f84ee30b77d53e1693378f#16-types-defaults-to-). "types": ["node"], "allowJs": true }, diff --git a/extensions/readme.md b/extensions/readme.md index 43f5254..4bdf0a7 100644 --- a/extensions/readme.md +++ b/extensions/readme.md @@ -1,5 +1,5 @@ `readme.py` - Overview of extensions -================================================================================ +==================================== The goal of the CodeChat Editor is to provide extensions for a number of IDEs and environments. To support this, an explicit design goal of the Editor is to diff --git a/server/.cargo/config.toml b/server/.cargo/config.toml index c5dd86a..62c59ce 100644 --- a/server/.cargo/config.toml +++ b/server/.cargo/config.toml @@ -1,11 +1,11 @@ # `config` - a Cargo configuration file -# ============================================================================== +# ===================================== # # See the [docs](https://doc.rust-lang.org/cargo/reference/config.html) for this # file. # # ts\_rs config -# ------------------------------------------------------------------------------ +# ------------- # # Configure the directory where `ts-rs` places the generated files per the docs. # See also the diff --git a/server/dist.toml b/server/dist.toml index 2af96cc..1ec4615 100644 --- a/server/dist.toml +++ b/server/dist.toml @@ -17,9 +17,9 @@ # [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/). # # `dist.toml` - Configure [cargo-dist](https://opensource.axo.dev/cargo-dist/) -# ============================================================================== +# ============================================================================ # -# Config for 'dist' +# Config for `dist`. [dist] # Extra static files to include in each App (path relative to this Cargo.toml's # dir) diff --git a/server/src/ide.rs b/server/src/ide.rs index 21037d9..50e87dc 100644 --- a/server/src/ide.rs +++ b/server/src/ide.rs @@ -14,12 +14,12 @@ // the CodeChat Editor. If not, see // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). /// `ide.rs` -- Provide interfaces with common IDEs -/// ============================================================================ +/// =============================================== pub mod filewatcher; pub mod vscode; // Imports -// ----------------------------------------------------------------------------- +// ------- // // ### Standard library use std::{ @@ -57,7 +57,7 @@ use crate::{ }; // Code -// ----------------------------------------------------------------------------- +// ---- // // Using this macro is critical -- otherwise, the Actix system doesn't get // correctly initialized, which makes calls to `actix_rt::spawn` fail. In diff --git a/server/src/ide/filewatcher.rs b/server/src/ide/filewatcher.rs index 79d00da..7e8d3c0 100644 --- a/server/src/ide/filewatcher.rs +++ b/server/src/ide/filewatcher.rs @@ -14,9 +14,9 @@ // the CodeChat Editor. If not, see // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). /// `filewatcher.rs` -- Implement the File Watcher "IDE" -/// ============================================================================ +/// ==================================================== // Imports -// ----------------------------------------------------------------------------- +// ------- // // ### Standard library use std::{ @@ -73,7 +73,7 @@ use crate::{ }; // Globals -// ----------------------------------------------------------------------------- +// ------- lazy_static! { /// Matches a bare drive letter. Only needed on Windows. static ref DRIVE_LETTER_REGEX: Regex = Regex::new("^[a-zA-Z]:$").unwrap(); @@ -82,7 +82,7 @@ lazy_static! { pub const FILEWATCHER_PATH_PREFIX: &[&str] = &["fw", "fsc"]; /// File browser endpoints -/// ---------------------------------------------------------------------------- +/// ---------------------- /// /// The file browser provides a very crude interface, allowing a user to select /// a file from the local filesystem for editing. Long term, this should be @@ -725,7 +725,7 @@ pub fn get_connection_id_raw(app_state: &WebAppState) -> u32 { } // Tests -// ----------------------------------------------------------------------------- +// ----- #[cfg(test)] mod tests { use std::{ diff --git a/server/src/ide/vscode.rs b/server/src/ide/vscode.rs index 5c431e5..77a21b5 100644 --- a/server/src/ide/vscode.rs +++ b/server/src/ide/vscode.rs @@ -15,14 +15,14 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). /// `vscode.rs` -- Implement server-side functionality for the Visual Studio /// Code IDE -/// ============================================================================ +/// ======================================================================== // Modules -// ----------------------------------------------------------------------------- +// ------- #[cfg(test)] pub mod tests; // Imports -// ----------------------------------------------------------------------------- +// ------- // // ### Standard library // @@ -53,12 +53,12 @@ use crate::{ }; // Globals -// ----------------------------------------------------------------------------- +// ------- const VSCODE_PATH_PREFIX: &[&str] = &["vsc", "fs"]; const VSC: &str = "vsc-"; // Code -// ----------------------------------------------------------------------------- +// ---- #[get("/vsc/ws-ide/{connection_id_raw}")] pub async fn vscode_ide_websocket( connection_id_raw: web::Path, diff --git a/server/src/ide/vscode/tests.rs b/server/src/ide/vscode/tests.rs index d9919b3..1670608 100644 --- a/server/src/ide/vscode/tests.rs +++ b/server/src/ide/vscode/tests.rs @@ -147,7 +147,7 @@ async fn connect_async_client(connection_id: &str) -> WebSocketStreamTcp { /// /// Message ids at function end: IDE - 4, Server - 3, Client - 2. async fn open_client(ws_ide: &mut WebSocketStream) { - // 1. Send the `Opened` message. + // 1. Send the `Opened` message. // // Message ids: IDE - 1->4, Server - 0, Client - 2. send_message( @@ -168,7 +168,7 @@ async fn open_client(ws_ide: &mut WebSocketSt } ); - // 2. Next, wait for the next message -- the HTML. + // 2. Next, wait for the next message -- the HTML. // // Message ids: IDE - 4, Server - 0->3, Client - 2. let em = read_message(ws_ide).await; @@ -973,7 +973,8 @@ async fn test_vscode_ide_websocket4() { // // Message ids: IDE - 0, Server - 2->3, Client - 0. // - // Since the version is randomly generated, copy that from the received message. + // Since the version is randomly generated, copy that from the received + // message. let msg = read_message(&mut ws_client).await; assert_eq!( msg, @@ -1061,7 +1062,9 @@ async fn test_vscode_ide_websocket4() { .await; join_handle.join().unwrap(); - // What makes sense here? If the IDE didn't load the file, either the Client shouldn't edit it or the Client should switch to using a filewatcher for edits. + // What makes sense here? If the IDE didn't load the file, either the Client + // shouldn't edit it or the Client should switch to using a filewatcher for + // edits. /*** // Send an update from the Client, which should produce a diff. // diff --git a/server/src/lexer.rs b/server/src/lexer.rs index e86396b..c261cf7 100644 --- a/server/src/lexer.rs +++ b/server/src/lexer.rs @@ -15,13 +15,13 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). mod pest_parser; /// `lexer.rs` -- Lex source code into code and doc blocks -/// ============================================================================ +/// ====================================================== // Submodule definitions -// ----------------------------------------------------------------------------- +// --------------------- pub mod supported_languages; // Imports -// ----------------------------------------------------------------------------- +// ------- // // ### Standard library #[cfg(feature = "lexer_explain")] @@ -36,7 +36,7 @@ use regex::Regex; use supported_languages::get_language_lexer_vec; /// Data structures -/// ---------------------------------------------------------------------------- +/// --------------- /// /// ### Language definition /// @@ -260,7 +260,7 @@ pub enum CodeDocBlock { } // Globals -// ----------------------------------------------------------------------------- +// ------- // // Create constant regexes needed by the lexer, following the // [Regex docs recommendation](https://docs.rs/regex/1.6.0/regex/index.html#example-avoid-compiling-the-same-regex-in-a-loop). @@ -596,7 +596,7 @@ fn build_lexer_regex( } // Compile lexers -// ----------------------------------------------------------------------------- +// -------------- pub fn compile_lexers(language_lexer_arr: Vec) -> LanguageLexersCompiled { let mut language_lexers_compiled = LanguageLexersCompiled { language_lexer_compiled_vec: Vec::new(), @@ -634,7 +634,7 @@ pub fn compile_lexers(language_lexer_arr: Vec) -> LanguageLexersC } /// Source lexer -/// ---------------------------------------------------------------------------- +/// ------------ /// /// This lexer categorizes source code into code blocks or doc blocks. /// @@ -1441,7 +1441,7 @@ pub fn source_lexer( } // Tests -// ----------------------------------------------------------------------------- +// ----- // // Rust // [almost mandates](https://doc.rust-lang.org/book/ch11-03-test-organization.html) diff --git a/server/src/lexer/pest/c.pest b/server/src/lexer/pest/c.pest index 295648e..51f4a3a 100644 --- a/server/src/lexer/pest/c.pest +++ b/server/src/lexer/pest/c.pest @@ -15,10 +15,10 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // // `c.pest` - Pest parser definition for the C language -// ============================================================================= +// ==================================================== // // Comments -// ----------------------------------------------------------------------------- +// -------- doc_block = _{ inline_comment | block_comment } // Per the @@ -50,7 +50,7 @@ block_comment_closing_delim_1 = { unused } block_comment_closing_delim_2 = { unused } // Code -// ----------------------------------------------------------------------------- +// ---- // // Per the // [C standard, section 5.1.1.2](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf#page=24), @@ -83,7 +83,7 @@ logical_line_char = _{ ("\\" ~ NEWLINE) | not_newline } code_line_token = _{ logical_line_char } // Dedenter -// ----------------------------------------------------------------------------- +// -------- // // This parser runs separately; it dedents block comments. There are several // cases: diff --git a/server/src/lexer/pest/python.pest b/server/src/lexer/pest/python.pest index e07812a..07b523d 100644 --- a/server/src/lexer/pest/python.pest +++ b/server/src/lexer/pest/python.pest @@ -15,7 +15,7 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // // `python.pest` - Pest parser definition for Python -// ============================================================================= +// ================================================= doc_block = _{ inline_comment } // Per the @@ -25,7 +25,7 @@ doc_block = _{ inline_comment } white_space = { (" " | "\t")* } // Inline comments -// ----------------------------------------------------------------------------- +// --------------- inline_comment_delims = _{ inline_comment_delim_0 } inline_comment_delim_0 = { "#" } inline_comment_delim_1 = { unused } @@ -37,7 +37,7 @@ inline_comment_delim_2 = { unused } inline_comment_char = { not_newline } // Block comments -// ----------------------------------------------------------------------------- +// -------------- // // Other languages support block comments; even though Python doesn't, the // following must be defined. Block comments never combine. @@ -50,7 +50,7 @@ block_comment_closing_delim_1 = { unused } block_comment_closing_delim_2 = { unused } // Code blocks -// ----------------------------------------------------------------------------- +// ----------- code_line_token = _{ long_string | short_string | not_newline } long_string = _{ // The opening string delimiter. @@ -73,7 +73,7 @@ short_string = _{ } // Dedenter -// ----------------------------------------------------------------------------- +// -------- dedenter = { unused } /// CodeChat Editor lexer: cpp. diff --git a/server/src/lexer/pest/shared.pest b/server/src/lexer/pest/shared.pest index 6abcfa7..1df626d 100644 --- a/server/src/lexer/pest/shared.pest +++ b/server/src/lexer/pest/shared.pest @@ -15,11 +15,11 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // // `shared.pest` - Pest parser definition shared by all languages -// ============================================================================= +// ============================================================== file = { SOI ~ (doc_block | code_block)* ~ EOI } // Inline comments -// ----------------------------------------------------------------------------- +// --------------- // // Use this approach to match a group of inline comments with the same // whitespace indentation. @@ -46,7 +46,7 @@ inline_comment_line = { (" " ~ inline_comment_body) | newline_eoi } inline_comment_body = { inline_comment_char* ~ newline_eoi } // Block comments -// ----------------------------------------------------------------------------- +// -------------- // // Support multiple opening and closing delimiters using some repetition. block_comment_0 = _{ @@ -72,12 +72,12 @@ optional_space = { " "? } block_comment_ending = { newline_eoi } // Code blocks -// ----------------------------------------------------------------------------- +// ----------- code_block = { code_line+ } code_line = _{ (!doc_block ~ code_line_token* ~ NEWLINE) | (!doc_block ~ code_line_token+ ~ EOI) } // Other commonly-used tokens -// ----------------------------------------------------------------------------- +// -------------------------- newline_eoi = _{ NEWLINE | EOI } not_newline = _{ !NEWLINE ~ ANY } // Indicates this token isn't used by the parser. diff --git a/server/src/lexer/pest_parser.rs b/server/src/lexer/pest_parser.rs index 4b1a43e..f3c0c53 100644 --- a/server/src/lexer/pest_parser.rs +++ b/server/src/lexer/pest_parser.rs @@ -15,10 +15,10 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // // `pest_parser.rs` -- Lex source code into code and doc blocks -// ============================================================================= +// ============================================================ // // Imports -// ----------------------------------------------------------------------------- +// ------- // // ### Standard library // @@ -32,7 +32,7 @@ // // None. /// Parser generator -/// ---------------------------------------------------------------------------- +/// ---------------- /// /// This macro generates a parser function that converts the provided string /// into a series of code and doc blocks. I'd prefer to use traits, but don't @@ -251,7 +251,7 @@ macro_rules! make_parse_block_comment { } // Parsers -// ----------------------------------------------------------------------------- +// ------- // // Each parser is kept in a separate module to avoid name conflicts, since Pest // generates a `Rule` enum for each grammar. @@ -280,7 +280,7 @@ pub mod python { } // Tests -// ----------------------------------------------------------------------------- +// ----- #[cfg(test)] mod test { use indoc::indoc; diff --git a/server/src/lexer/supported_languages.rs b/server/src/lexer/supported_languages.rs index f95f310..f0c27a6 100644 --- a/server/src/lexer/supported_languages.rs +++ b/server/src/lexer/supported_languages.rs @@ -15,13 +15,13 @@ /// [http://www.gnu.org/licenses](http://www.gnu.org/licenses). /// /// `supported_languages.rs` - Provide lexer info for all supported languages -/// ============================================================================ +/// ========================================================================= /// /// This file contains a data structure which describes all supported languages; /// the [lexer](../lexer.rs) uses this lex a given language. /// /// Lexer implementation -/// ---------------------------------------------------------------------------- +/// -------------------- /// /// Ordering matters: all these delimiters end up in a large regex separated by /// an or operator. The regex or operator matches from left to right. So, longer @@ -45,7 +45,7 @@ /// doesn't parse the string correctly, it does correctly identify where /// comments can't be, which is all that the lexer needs to do. // Imports -// ----------------------------------------------------------------------------- +// ------- // // ### Standard library use std::sync::Arc; @@ -59,7 +59,7 @@ use super::{ pub const MARKDOWN_MODE: &str = "markdown"; // Helper functions -// ----------------------------------------------------------------------------- +// ---------------- // // These functions simplify the syntax needed to create a `LanguageLexer`. #[allow(clippy::too_many_arguments)] @@ -125,7 +125,7 @@ fn make_block_comment_delim(opening: &str, closing: &str, is_nestable: bool) -> } // Define lexers for each supported language. -// ----------------------------------------------------------------------------- +// ------------------------------------------ pub fn get_language_lexer_vec() -> Vec { vec![ // ### Linux shell scripts diff --git a/server/src/lexer/tests.rs b/server/src/lexer/tests.rs index b72eede..b9ea6d8 100644 --- a/server/src/lexer/tests.rs +++ b/server/src/lexer/tests.rs @@ -15,9 +15,9 @@ /// [http://www.gnu.org/licenses](http://www.gnu.org/licenses). /// /// `test.rs` -- Unit tests for the lexer -/// ============================================================================ +/// ===================================== // Imports -// ----------------------------------------------------------------------------- +// ------- use super::supported_languages::get_language_lexer_vec; use super::{CodeDocBlock, DocBlock, compile_lexers, source_lexer}; use indoc::indoc; @@ -25,7 +25,7 @@ use pretty_assertions::assert_eq; use test_utils::test_utils::stringit; // Utilities -// ----------------------------------------------------------------------------- +// --------- // // Provide a compact way to create a `CodeDocBlock`. fn build_doc_block(indent: &str, delimiter: &str, contents: &str) -> CodeDocBlock { diff --git a/server/src/lib.rs b/server/src/lib.rs index 7e178fc..16e71f1 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -15,7 +15,7 @@ /// [http://www.gnu.org/licenses](http://www.gnu.org/licenses). /// /// `lib.rs` -- Define library modules for the CodeChat Editor Server -/// ============================================================================ +/// ================================================================= /// /// TODO: Add the ability to use /// [plugins](https://zicklag.github.io/rust-tutorials/rust-plugins.html). diff --git a/server/src/main.rs b/server/src/main.rs index 276002a..ec00937 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -14,9 +14,9 @@ // the CodeChat Editor. If not, see // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). /// `main.rs` -- Entrypoint for the CodeChat Editor Server -/// ============================================================================ +/// ====================================================== // Imports -// ----------------------------------------------------------------------------- +// ------- // // ### Standard library use std::{ @@ -39,7 +39,7 @@ use log::LevelFilter; use code_chat_editor::webserver::{self, Credentials, GetServerUrlError, path_to_url}; // Data structures -// ----------------------------------------------------------------------------- +// --------------- // // ### Command-line interface // @@ -94,7 +94,7 @@ enum Commands { } // Code -// ----------------------------------------------------------------------------- +// ---- // // The following code implements the command-line interface for the CodeChat // Editor. diff --git a/server/src/processing.rs b/server/src/processing.rs index 2d9073f..a3d3268 100644 --- a/server/src/processing.rs +++ b/server/src/processing.rs @@ -15,9 +15,9 @@ // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). /// `processing.rs` -- Transform source code to its web-editable equivalent and /// back -/// ============================================================================ +/// =========================================================================== // Imports -// ----------------------------------------------------------------------------- +// ------- // // ### Standard library // @@ -76,7 +76,7 @@ use crate::lexer::{ }; // Data structures -// ----------------------------------------------------------------------------- +// --------------- // // ### Translation between a local (traditional) source file and its web-editable, client-side representation // @@ -249,7 +249,7 @@ pub enum TranslationResultsString { // On save, the process is CodeChatForWeb -> Vec\ -> source code. // // Globals -// ----------------------------------------------------------------------------- +// ------- lazy_static! { /// Match the lexer directive in a source file. static ref LEXER_DIRECTIVE: Regex = Regex::new(r"CodeChat Editor lexer: (\w+)").unwrap(); @@ -328,7 +328,7 @@ const WORD_WRAP_COLUMN: usize = 80; const WORD_WRAP_MIN_WIDTH: usize = 40; // Serialization for `CodeMirrorDocBlock` -// ----------------------------------------------------------------------------- +// -------------------------------------- #[derive(Serialize, Deserialize, TS)] #[ts(export)] struct CodeMirrorDocBlockTuple<'a>( @@ -380,7 +380,7 @@ impl<'de> Deserialize<'de> for CodeMirrorDocBlock { } // Determine if the provided file is part of a project -// ----------------------------------------------------------------------------- +// --------------------------------------------------- pub fn find_path_to_toc(file_path: &Path) -> Option { // To determine if this source code is part of a project, look for a project // file by searching the current directory, then all its parents, for a file @@ -420,7 +420,7 @@ pub enum CodechatForWebToSourceError { } // Transform `CodeChatForWeb` to source code -// ----------------------------------------------------------------------------- +// ----------------------------------------- /// This function takes in a source file in web-editable format (the /// `CodeChatForWeb` struct) and transforms it into source code. pub fn codechat_for_web_to_source( @@ -814,7 +814,7 @@ pub enum SourceToCodeChatForWebError { } // Transform from source code to `CodeChatForWeb` -// ----------------------------------------------------------------------------- +// ---------------------------------------------- // // Given the contents of a file, classify it and (for CodeChat Editor files) // convert it to the `CodeChatForWeb` format. @@ -1840,6 +1840,6 @@ fn html_analyze( */ // Tests -// ----------------------------------------------------------------------------- +// ----- #[cfg(test)] mod tests; diff --git a/server/src/webserver.rs b/server/src/webserver.rs index 682e2a9..070fe1b 100644 --- a/server/src/webserver.rs +++ b/server/src/webserver.rs @@ -14,14 +14,14 @@ // the CodeChat Editor. If not, see // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). /// `webserver.rs` -- Serve CodeChat Editor Client webpages -/// ============================================================================ +/// ======================================================= // Submodules -// ----------------------------------------------------------------------------- +// ---------- #[cfg(test)] pub mod tests; // Imports -// ----------------------------------------------------------------------------- +// ------- // // ### Standard library use std::{ @@ -96,7 +96,7 @@ use crate::{ }; // Data structures -// ----------------------------------------------------------------------------- +// --------------- // // ### Data structures supporting a websocket connection between the IDE, this // @@ -392,7 +392,7 @@ pub struct Credentials { } // Macros -// ----------------------------------------------------------------------------- +// ------ /// Create a macro to report an error when enqueueing an item. #[macro_export] macro_rules! queue_send { @@ -421,7 +421,7 @@ macro_rules! queue_send_func { } /// Globals -/// ---------------------------------------------------------------------------- +/// ------- // The timeout for a reply from a websocket, in ms. Use a short timeout to speed // up unit tests. pub const REPLY_TIMEOUT_MS: Duration = if cfg!(test) { @@ -563,7 +563,7 @@ pub fn set_root_path( } // Webserver functionality -// ----------------------------------------------------------------------------- +// ----------------------- #[get("/ping")] async fn ping() -> HttpResponse { HttpResponse::Ok().body("pong") @@ -1124,7 +1124,7 @@ fn make_simple_viewer(http_request: &ProcessingTaskHttpRequest, html: &str) -> S } /// Websockets -/// ---------------------------------------------------------------------------- +/// ---------- /// /// Each CodeChat Editor IDE instance pairs with a CodeChat Editor Client /// through the CodeChat Editor Server. Together, these form a joint editor, @@ -1391,7 +1391,7 @@ pub fn client_websocket( } // Webserver core -// ----------------------------------------------------------------------------- +// -------------- #[actix_web::main] pub async fn main( extension_base_path: Option<&Path>, @@ -1553,7 +1553,7 @@ where } // Utilities -// ----------------------------------------------------------------------------- +// --------- // // Send a response to the client after processing a message from the client. pub async fn send_response(client_tx: &Sender, id: f64, result: MessageResult) { diff --git a/server/src/webserver/tests.rs b/server/src/webserver/tests.rs index 41ce140..c47a49a 100644 --- a/server/src/webserver/tests.rs +++ b/server/src/webserver/tests.rs @@ -14,9 +14,9 @@ // the CodeChat Editor. If not, see // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). /// `test.rs` -- Unit tests for the vscode interface -/// ============================================================================ +/// ================================================ // Imports -// ----------------------------------------------------------------------------- +// ------- // // ### Standard library use std::path::{MAIN_SEPARATOR_STR, PathBuf}; @@ -34,7 +34,7 @@ use crate::ide::{filewatcher::FILEWATCHER_PATH_PREFIX, vscode::tests::IP_PORT}; use test_utils::{cast, prep_test_dir}; // Support functions -// ----------------------------------------------------------------------------- +// ----------------- // // The lint on using `cargo_bin` doesn't apply, since this is only available for // integration tests per the @@ -52,7 +52,7 @@ fn get_server() -> Command { } // Tests -// ----------------------------------------------------------------------------- +// ----- #[test] fn test_url_to_path() { let (temp_dir, test_dir) = prep_test_dir!(); diff --git a/server/tests/cli.rs b/server/tests/cli.rs index 0f3fca9..4d94ade 100644 --- a/server/tests/cli.rs +++ b/server/tests/cli.rs @@ -14,9 +14,9 @@ // the CodeChat Editor. If not, see // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). /// `cli.rs` - Test the CLI interface -/// ============================================================================ +/// ================================= // Imports -// ----------------------------------------------------------------------------- +// ------- // // ### Standard library // @@ -31,7 +31,7 @@ use predicates::{prelude::predicate, str::contains}; use tokio::task::spawn_blocking; // Support functions -// ----------------------------------------------------------------------------- +// ----------------- // // The lint on using `cargo_bin` doesn't apply, since this is only available for // integration tests per the @@ -48,7 +48,7 @@ fn get_server() -> Command { } // Tests -// ----------------------------------------------------------------------------- +// ----- #[test] fn test_start_not_found() { let mut cmd = get_server(); diff --git a/test_utils/readme.md b/test_utils/readme.md index 74a0e0e..f3eadf9 100644 --- a/test_utils/readme.md +++ b/test_utils/readme.md @@ -1,5 +1,5 @@ `readme.md` - Overview of test utilities -================================================================================ +======================================== These test utilities are used both in unit tests and in integration tests. Integration tests can't access code inside a `#[cfg(test)]` configuration diff --git a/test_utils/src/test_macros.rs b/test_utils/src/test_macros.rs index b1220e8..1df3d2e 100644 --- a/test_utils/src/test_macros.rs +++ b/test_utils/src/test_macros.rs @@ -15,14 +15,14 @@ /// [http://www.gnu.org/licenses](http://www.gnu.org/licenses). /// /// `test_macros.rs` -- Reusable macros for testing -/// ============================================================================ +/// =============================================== // Imports -// ----------------------------------------------------------------------------- +// ------- // // None. // // Macros -// ----------------------------------------------------------------------------- +// ------ // // Extract a known enum variant or fail. More concise than the alternative (`if // let`, or `let else`). From [SO](https://stackoverflow.com/a/69324393). The diff --git a/test_utils/src/test_utils.rs b/test_utils/src/test_utils.rs index a947b3c..352590c 100644 --- a/test_utils/src/test_utils.rs +++ b/test_utils/src/test_utils.rs @@ -15,9 +15,9 @@ /// [http://www.gnu.org/licenses](http://www.gnu.org/licenses). /// /// `test_utils.rs` -- Reusable routines for testing. -/// ============================================================================ +/// ================================================= // Imports -// ----------------------------------------------------------------------------- +// ------- // // ### Standard library use std::env; @@ -33,7 +33,7 @@ use log::Level; use crate::testing_logger; // Macros -// ----------------------------------------------------------------------------- +// ------ // // Extract a known enum variant or fail. More concise than the alternative (`if // let`, or `let else`). From [SO](https://stackoverflow.com/a/69324393). The @@ -97,7 +97,7 @@ macro_rules! prep_test_dir { } // Code -// ----------------------------------------------------------------------------- +// ---- // // Use the `tests/fixtures` path (relative to the root of this Rust project) to // store files for testing. A subdirectory tree, named by the module path then diff --git a/test_utils/src/testing_logger.rs b/test_utils/src/testing_logger.rs index 03edb37..94ba23d 100644 --- a/test_utils/src/testing_logger.rs +++ b/test_utils/src/testing_logger.rs @@ -1,5 +1,5 @@ // `testing_logger.rs` -- a logger to support unit testing. -// ============================================================================= +// ======================================================== // // This is a minimally-modified version of the // [testing\_logger](https://github.com/brucechapman/rust_testing_logger) crate: @@ -47,7 +47,7 @@ //! captured log messages. //! //! Examples -//! ============================================================================ +//! ======== //! //! ``` //! #[macro_use] diff --git a/toc.md b/toc.md index f591682..7dc9408 100644 --- a/toc.md +++ b/toc.md @@ -1,21 +1,21 @@ The CodeChat Editor -================================================================================ +=================== User documentation -================================================================================ +================== * [The CodeChat Editor manual](README.md) * [The CodeChat Editor extension for Visual Studio Code manual](extensions/VSCode/README.md) * [Literate programming using the CodeChat Editor](docs/style_guide.cpp) Design -================================================================================ +====== * [CodeChat Editor Design](docs/design.md) * [Implementation](docs/implementation.md) Implementation -================================================================================ +============== * [Server](server/readme.md) * [main.rs](server/src/main.rs) @@ -101,7 +101,7 @@ Implementation * [dist.toml](server/dist.toml) - additional cargo-dist configuration Misc -================================================================================ +==== * [New project template](new-project-template/README.md) * [Table of contents](toc.md) From 970e35307977139f1ba081dcb1ecf3d1c5f71810 Mon Sep 17 00:00:00 2001 From: "Bryan A. Jones" Date: Fri, 10 Apr 2026 16:58:36 +0500 Subject: [PATCH 4/9] Fix: broken links. --- toc.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/toc.md b/toc.md index 7dc9408..3ba2d6f 100644 --- a/toc.md +++ b/toc.md @@ -52,7 +52,7 @@ Implementation * [CodeChatEditor.mts](client/src/CodeChatEditor.mts) * [CodeMirror-integration.mts](client/src/CodeMirror-integration.mts) * [tinymce-config.mts](client/src/tinymce-config.mts) - * [graphviz-webcomponent-setup.mjs](client/src/graphviz-webcomponent-setup.mts) + * [graphviz-webcomponent-setup.mjs](client/src/graphviz-webcomponent-setup.mjs) * [Mermaid](client/src/third-party/wc-mermaid/developer.md) * [shared\_types.mts](client/src/shared_types.mts) * [assert.mts](client/src/assert.mts) @@ -76,8 +76,8 @@ Implementation * [Developer documentation](extensions/VSCode/developer.md) * Development tools * Builder - * [builder/Cargo.toml](Cargo.toml) - * [builder/src/main.rs](main.rs) + * [builder/Cargo.toml](builder/Cargo.toml) + * [builder/src/main.rs](builder/src/main.rs) * Git * [server/.gitignore](server/.gitignore) * [client/static/.gitignore](client/static/.gitignore) From 01f1f37976598873a12f7f2a545d374406d6ee58 Mon Sep 17 00:00:00 2001 From: "Bryan A. Jones" Date: Fri, 10 Apr 2026 16:58:56 +0500 Subject: [PATCH 5/9] squash: claude review. --- server/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/server/Cargo.toml b/server/Cargo.toml index 1bffd64..741b7fa 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -68,6 +68,7 @@ futures-util = "0.3.29" htmd = { git = "https://github.com/bjones1/htmd.git", branch = "dom-interface", version = "0.5" } # This must match the version of `markup5ever_rcdom`. html5ever = "0.38" +htmlize = "1.0.6" imara-diff = { version = "0.2", features = [] } indoc = "2.0.5" lazy_static = "1" From e54fab409e41418edb97062d1d55fe4ebe37fef8 Mon Sep 17 00:00:00 2001 From: "Bryan A. Jones" Date: Fri, 10 Apr 2026 17:01:52 +0500 Subject: [PATCH 6/9] Clean: preliminary thoughts superseded by the cache. --- server/src/processing.rs | 219 --------------------------------------- 1 file changed, 219 deletions(-) diff --git a/server/src/processing.rs b/server/src/processing.rs index a3d3268..403cd05 100644 --- a/server/src/processing.rs +++ b/server/src/processing.rs @@ -20,15 +20,6 @@ // ------- // // ### Standard library -// -// For commented-out caching code. -/** -use std::collections::{HashMap, HashSet}; -use std::fs::Metadata; -use std::io; -use std::ops::Deref; -use std::rc::{Rc, Weak}; -*/ use std::{ borrow::Cow, cell::RefCell, @@ -1629,216 +1620,6 @@ pub fn diff_code_mirror_doc_blocks( change_specs } -// Goal: make it easy to update the data structure. We update on every -// load/save, then do some accesses during those processes. -// -// Top-level data structures: a file HashSet\ and an id -// HashMap\}>. Some FileAnchors in the file -// HashSet are also in a pending load list.. -// -// * To update a file: -// * Remove the old file from the file HasHMap. Add an empty FileAnchor to the -// file HashMap. -// * For each id, see if that id already exists. -// * If the id exists: if it refers to an id in the old FileAnchor, replace -// it with the new one. If not, need to perform resolution on this id (we -// have a non-unique id; how to fix?). -// * If the id doesn't exist: create a new one. -// * For each hyperlink, see if that id already exists. -// * If so, upsert the referring id. Check the metadata on the id to make -// sure that data is current. If not, add this to the pending hyperlinks -// list. If the file is missing, delete it from the cache. -// * If not, create a new entry in the id HashSet and add the referring id -// to the HashSet. Add the file to a pending hyperlinks list. -// * When the file is processed: -// * Look for all entries in the pending file list that refer to the current -// file and resolve these. Start another task to load in all pending -// files. -// * Look at the old file; remove each id that's still in the id HashMap. If -// the id was in the HashMap and it also was a Hyperlink, remove that from -// the HashSet. -// * To remove a file from the HashMap: -// * Remove it from the file HashMap. -// * For each hyperlink, remove it from the HashSet of referring links (if -// that id still exists). -// * For each id, remove it from the id HashMap. -// * To add a file from the HashSet: -// * Perform an update with an empty FileAnchor. -// -// Pending hyperlinks list: for each hyperlink, -// -// * check if the id is now current in the cache. If so, add the referring id to -// the HashSet then move to the next hyperlink. -// * check if the file is now current in the cache. If not, load the file and -// update the cache, then go to step 1. -// * The id was not found, even in the expected file. Add the hyperlink to a -// broken links set? -// -// Global operations: -// -// * Scan all files, then perform add/upsert/removes based on differences with -// the cache. -// -// Functions: -// -// * Upsert an Anchor. -// * Upsert a Hyperlink. -// * Upsert a file. -// * Remove a file. -/*x -/// There are two types of files that can serve as an anchor: these are file -/// anchor targets. -enum FileAnchor { - Plain(PlainFileAnchor), - Html(HtmlFileAnchor), -} - -/// This is the cached metadata for a file that serves as an anchor: perhaps an -/// image, a PDF, or a video. -struct PlainFileAnchor { - /// A relative path to this file, rooted at the project's TOC. - path: Rc, - /// The globally-unique anchor used to link to this file. It's generated - /// based on hash of the file's contents, so that each file will have a - /// unique identifier. - anchor: String, - /// Metadata captured when this data was cached. If it disagrees with the - /// file's current state, then this cached data should be re=generated from - /// the file. - file_metadata: Metadata, -} - -/// Cached metadata for an HTML file. -struct HtmlFileAnchor { - /// The file containing this HTML. - file_anchor: PlainFileAnchor, - /// The TOC numbering of this file. - numbering: Vec>, - /// The headings in this file. - headings: Vec, - /// Anchors which appear before the first heading. - pre_anchors: Vec, -} - -/// Cached metadata shared by both headings (which are also anchors) and -/// non-heading anchors. -struct AnchorCommon { - /// The HTML file containing this anchor. - html_file_anchor: Weak, - /// The globally-unique anchor used to link to this object. - anchor: String, - /// The inner HTML of this anchor. - inner_html: String, - /// The hyperlink this anchor contains. - hyperlink: Option>, -} - -/// An anchor is defined only in these two places: the anchor source. -enum HtmlAnchor { - Heading(HeadingAnchor), - NonHeading(NonHeadingAnchor), -} - -/// Cached metadata for a heading (which is always also an anchor). -struct HeadingAnchor { - anchor_common: AnchorCommon, - /// The numbering of this heading on the HTML file containing it. - numbering: Vec>, - /// Non-heading anchors which appear after this heading but before the next - /// heading. - non_heading_anchors: Vec, -} - -/// Cached metadata for a non-heading anchor. -struct NonHeadingAnchor { - anchor_common: AnchorCommon, - /// The heading this anchor appears after (unless it appears before the - /// first heading in this file). - parent_heading: Option>, - /// A snippet of HTML preceding this anchor. - pre_snippet: String, - /// A snippet of HTML following this anchor. - post_snippet: String, - /// If this is a numbered item, the name of the numbering group it belongs - /// to. - numbering_group: Option, - /// If this is a numbered item, its number. - number: u32, -} - -/// An anchor can refer to any of these structs: these are all possible anchor -/// targets. -enum Anchor { - Html(HtmlAnchor), - File(FileAnchor), -} - -/// The metadata for a hyperlink. -struct Hyperlink { - /// The file this hyperlink refers to. - file: PathBuf, - /// The anchor this hyperlink refers to. - html_anchor: String, -} - -/// The value stored in the id HashMap. -struct AnchorVal { - /// The target anchor this id refers to. - anchor: Anchor, - /// All hyperlinks which target this anchor. - referring_links: Rc>, -} - -// Given HTML, catalog all link targets and link-like items, ensuring that they -// have a globally unique id. -fn html_analyze( - file_path: &Path, - html: &str, - mut file_map: HashMap, Rc>, - mut anchor_map: HashMap, HashSet>, -) -> io::Result { - // Create the missing anchors: - // - // A missing file. - let missing_html_file_anchor = Rc::new(FileAnchor::Html(HtmlFileAnchor { - file_anchor: PlainFileAnchor { - path: Rc::new(PathBuf::new()), - anchor: "".to_string(), - // TODO: is there some way to create generic/empty metadata? - file_metadata: Path::new(".").metadata().unwrap(), - }, - numbering: Vec::new(), - headings: Vec::new(), - pre_anchors: Vec::new(), - })); - // Define an anchor in this file. - let missing_anchor = NonHeadingAnchor { - anchor_common: AnchorCommon { - html_file_anchor: Rc::downgrade(&missing_html_file_anchor), - anchor: "".to_string(), - hyperlink: None, - inner_html: "".to_string(), - }, - parent_heading: None, - pre_snippet: "".to_string(), - post_snippet: "".to_string(), - numbering_group: None, - number: 0, - }; - // Add this to the top-level hashes. - let anchor_val = AnchorVal { - anchor: Anchor::Html(HtmlAnchor::NonHeading(missing_anchor)), - referring_links: Rc::new(HashSet::new()), - }; - //file_map.insert(mfa.file_anchor.path, missing_html_file_anchor); - //let anchor_val_set: HashSet = HashSet::new(); - //anchor_val_set.insert(anchor_val); - //anchor_map.insert(&mfa.file_anchor.anchor, anchor_val_set); - - Ok("".to_string()) -} -*/ - // Tests // ----- #[cfg(test)] From 42a0bcea9add1209e7267debb8e6c230bcae1a31 Mon Sep 17 00:00:00 2001 From: "Bryan A. Jones" Date: Tue, 14 Apr 2026 14:45:24 +0500 Subject: [PATCH 7/9] Fix: issues found by Claude. --- CHANGELOG.md | 25 ++++- builder/src/main.rs | 14 ++- client/package.json5 | 14 ++- client/src/CodeChatEditor-test.mts | 2 +- client/src/CodeChatEditor.mts | 60 +++++----- client/src/CodeChatEditorFramework.mts | 10 +- client/src/CodeMirror-integration.mts | 114 ++++++++++++------- client/src/HashReader.mts | 18 +-- client/src/{shared_types.mts => shared.mts} | 8 +- client/src/show_toast.mts | 1 + extensions/VSCode/src/extension.ts | 22 ++-- extensions/VSCode/src/lib.rs | 3 +- server/src/ide.rs | 38 +++++-- server/src/ide/filewatcher.rs | 22 ++-- server/src/ide/vscode.rs | 21 ++-- server/src/ide/vscode/tests.rs | 4 +- server/src/lexer.rs | 51 +++++---- server/src/lexer/pest/c.pest | 2 +- server/src/lexer/pest_parser.rs | 37 +++---- server/src/lexer/supported_languages.rs | 45 ++++---- server/src/lexer/tests.rs | 13 ++- server/src/main.rs | 49 +++++---- server/src/processing.rs | 41 +++---- server/src/processing/tests.rs | 116 +++++++++++--------- server/src/translation.rs | 27 ++--- server/src/webserver.rs | 8 +- test_utils/src/test_macros.rs | 24 ++-- test_utils/src/test_utils.rs | 12 +- test_utils/src/testing_logger.rs | 13 +-- toc.md | 2 +- 30 files changed, 463 insertions(+), 353 deletions(-) rename client/src/{shared_types.mts => shared.mts} (91%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41989a8..b4a2d34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,30 @@ Changelog [Github master](https://github.com/bjones1/CodeChat_Editor) ----------------------------------------------------------- -* No changes. +* Claude code reviews revealed the following issues, which were fixed manually: + * Fix multi-byte Unicode encoding bug. + * Fix incorrect websocket shutdown sequence. + * On websocket disconnect and reconnect, correctly retain timeouts for + responses. + * Change websocket response timeout to a reasonable value. + * Provide better error reporting when `hashLocations.json` file isn't found. + * Improve encoder performance. + * Correct bug in diff computation. + * Correctly handle CRLFs in files that begin with a LF. + * Fix several XSS vulnerabilities. + * Remove redundant reference counting on shared state. + * Avoid panics when validating passwords and when converting paths to strings. + * Fix bugs in nested comment parser. + * Improve CLI interface with better userid/password parsing, error reporting, + and ipv6 support. + * Include Windows drive letter Z when looking for available drives. + * Use block comment delimiter found in code, not a hard-coded C-only + delimiter. + * Correct many errors in the grammar for supported languages. + * Add lexer support for shell scripts, Swift, TOML, and Verilog, and VHDL. + * Ensure math is re-typeset after saving the document. + * Delay math un-typesetting until all typesetting is complete. + * Improve error reporting in VSCode extension. Version 0.1.52 -- 2026-Apr-09 ----------------------------- diff --git a/builder/src/main.rs b/builder/src/main.rs index 4b6080c..2a6b366 100644 --- a/builder/src/main.rs +++ b/builder/src/main.rs @@ -249,7 +249,7 @@ fn quick_copy_dir>(src: P, dest: P, files: Option

) -> io::Resu // Per // [these docs](https://learn.microsoft.com/en-us/troubleshoot/windows-server/backup-and-storage/return-codes-used-robocopy-utility), // check the return code. - if cfg!(windows) && exit_code >= 8 || !cfg!(windows) && exit_code != 0 { + if (cfg!(windows) && exit_code >= 8) || (!cfg!(windows) && exit_code != 0) { Err(io::Error::other(format!( "Copy process return code {exit_code} indicates failure." ))) @@ -271,6 +271,8 @@ fn remove_dir_all_if_exists + std::fmt::Display>(path: P) -> io:: Ok(()) } +/// Search and replace a file using the regex. It's currently only used to +/// update the version of a file; it does only one replacement. fn search_and_replace_file< P: AsRef + std::fmt::Display, S1: AsRef + std::fmt::Display, @@ -283,6 +285,8 @@ fn search_and_replace_file< let file_contents = fs::read_to_string(&path)?; let re = Regex::new(search_regex.as_ref()) .map_err(|err| io::Error::other(format!("Error in search regex {search_regex}: {err}")))?; + // Note that this does only one replacement -- there should be exactly one + // version number to replace in a file. let file_contents_replaced = re.replace(&file_contents, replace_string.as_ref()); assert_ne!( file_contents, file_contents_replaced, @@ -413,7 +417,7 @@ fn run_install(dev: bool) -> io::Result<()> { cargo binstall cargo-outdated --no-confirm; info "cargo binstall cargo-sort"; cargo binstall cargo-sort --no-confirm; - info "cargo binstall cargo-audio"; + info "cargo binstall cargo-audit"; cargo binstall cargo-audit --no-confirm; )?; } @@ -427,7 +431,7 @@ fn run_update() -> io::Result<()> { run_cmd!( info "Builder: cargo update"; cargo update --manifest-path=$BUILDER_PATH/Cargo.toml; - info "VSCoe extension: cargo update"; + info "VSCode extension: cargo update"; cargo update --manifest-path=$VSCODE_PATH/Cargo.toml; info "test_utils: cargo update" cargo update --manifest-path=$TEST_UTILS_PATH/Cargo.toml; @@ -478,7 +482,7 @@ fn run_format_and_lint(check_only: bool) -> io::Result<()> { cargo audit --file=$BUILDER_PATH/Cargo.lock --no-fetch; info "VSCode extension: cargo audit"; cargo audit --file=$VSCODE_PATH/Cargo.lock --no-fetch; - info "test_utils: cargo clippy and fmt" + info "test_utils: cargo audit" cargo audit --file=$TEST_UTILS_PATH/Cargo.lock --no-fetch; info "cargo sort"; @@ -578,7 +582,7 @@ fn run_client_build( true, )?; - // \The PDF viewer for use with VSCode. Build it separately, // since it's loaded apart from the rest of the Client. run_script( &esbuild, diff --git a/client/package.json5 b/client/package.json5 index c48f788..fd03274 100644 --- a/client/package.json5 +++ b/client/package.json5 @@ -60,6 +60,8 @@ '@codemirror/lang-sql': '^6.10.0', '@codemirror/lang-xml': '^6.1.0', '@codemirror/lang-yaml': '^6.1.3', + '@codemirror/language': '^6.12.3', + '@codemirror/legacy-modes': '^6.5.2', '@codemirror/state': '^6.6.0', '@codemirror/view': '6.38.8', '@hpcc-js/wasm-graphviz': '^1.21.2', @@ -79,20 +81,20 @@ '@types/mocha': '^10.0.10', '@types/node': '^24.12.2', '@types/toastify-js': '^1.12.4', - '@typescript-eslint/eslint-plugin': '^8.58.1', - '@typescript-eslint/parser': '^8.58.1', + '@typescript-eslint/eslint-plugin': '^8.58.2', + '@typescript-eslint/parser': '^8.58.2', chai: '^6.2.2', esbuild: '^0.28.0', eslint: '^10.2.0', 'eslint-config-prettier': '^10.1.8', 'eslint-plugin-import': '^2.32.0', 'eslint-plugin-prettier': '^5.5.5', - globals: '^17.4.0', + globals: '^17.5.0', mocha: '^11.7.5', - 'npm-check-updates': '^20.0.0', - prettier: '^3.8.1', + 'npm-check-updates': '^20.0.2', + prettier: '^3.8.2', typescript: '^6.0.2', - 'typescript-eslint': '^8.58.1', + 'typescript-eslint': '^8.58.2', }, scripts: { test: 'echo "Error: no test specified" && exit 1', diff --git a/client/src/CodeChatEditor-test.mts b/client/src/CodeChatEditor-test.mts index 3f7346c..999953d 100644 --- a/client/src/CodeChatEditor-test.mts +++ b/client/src/CodeChatEditor-test.mts @@ -27,7 +27,7 @@ import "mocha/mocha.js"; import "mocha/mocha.css"; import { EditorView } from "@codemirror/view"; import { ChangeSpec, EditorState, EditorSelection } from "@codemirror/state"; -import { CodeMirror, CodeMirrorDocBlockTuple } from "./shared_types.mjs"; +import { CodeMirror, CodeMirrorDocBlockTuple } from "./shared.mjs"; import { DocBlockPlugin, CodeMirror_JSON_fields, diff --git a/client/src/CodeChatEditor.mts b/client/src/CodeChatEditor.mts index 6f1bb02..59411f8 100644 --- a/client/src/CodeChatEditor.mts +++ b/client/src/CodeChatEditor.mts @@ -71,7 +71,7 @@ import { CodeMirror, autosave_timeout_ms, rand, -} from "./shared_types.mjs"; +} from "./shared.mjs"; import { show_toast } from "./show_toast.mjs"; // ### CSS @@ -257,10 +257,10 @@ const _open_lp = async ( // Get the mode from the page's query parameters. Default to edit using // the // [nullish coalescing operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator). - // TODO: this isn't typesafe, since the `mode` might not be a key of - // `EditorMode`. - /// @ts-expect-error("See above.") - const _editorMode = EditorMode[urlParams.get("mode") ?? "edit"]; + const mode = urlParams.get("mode") ?? EditorMode.edit; + const _editorMode = Object.values(EditorMode).includes(mode) + ? mode + : EditorMode.edit; // Get the [current_metadata](#current_metadata) from the // provided `code_chat_for_web` struct and store it as a global @@ -372,7 +372,11 @@ const _open_lp = async ( } }; -const save_lp = async (is_dirty: boolean) => { +const save_lp = async ( + // Avoid relying on the global `is_dirty`, which may change during an + // `await`. + is_dirty_now: boolean, +) => { const update: UpdateMessageContents = { // The Framework will fill in this value. file_path: "", @@ -385,7 +389,7 @@ const save_lp = async (is_dirty: boolean) => { } // Add the contents only if the document is dirty. - if (is_dirty) { + if (is_dirty_now) { /// @ts-expect-error("Declare here; it will be completed later.") let code_mirror_diffable: CodeMirrorDiffable = {}; if (is_doc_only()) { @@ -394,20 +398,25 @@ const save_lp = async (is_dirty: boolean) => { "CodeChat-body", ) as HTMLDivElement; mathJaxUnTypeset(codechat_body); - // To save a document only, simply get the HTML from the only Tiny - // MCE div. Update the `doc_contents` to stay in sync with the - // Server. - doc_content = tinymce.activeEditor!.save(); - ( - code_mirror_diffable as { - Plain: CodeMirror; - } - ).Plain = { - doc: doc_content, - doc_blocks: [], - }; - // Retypeset all math after saving the document. - await mathJaxTypeset(codechat_body); + // Use a try/finally to ensure that the document is retypeset even + // if errors occur. + try { + // To save a document only, simply get the HTML from the only + // Tiny MCE div. Update the `doc_contents` to stay in sync with + // the Server. + doc_content = tinymce.activeEditor!.save(); + ( + code_mirror_diffable as { + Plain: CodeMirror; + } + ).Plain = { + doc: doc_content, + doc_blocks: [], + }; + } finally { + // Retypeset all math after saving the document. + await mathJaxTypeset(codechat_body); + } } else { code_mirror_diffable = CodeMirror_save(); assert("Plain" in code_mirror_diffable); @@ -518,15 +527,6 @@ export const restoreSelection = ({ } }; -// Per -// [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/platform#examples), -// here's the least bad way to choose between the control key and the command -// key. -const _os_is_osx = - navigator.platform.indexOf("Mac") === 0 || navigator.platform === "iPhone" - ? true - : false; - // Save CodeChat Editor contents. const on_save = async (only_if_dirty: boolean = false) => { if (only_if_dirty && !is_dirty) { diff --git a/client/src/CodeChatEditorFramework.mts b/client/src/CodeChatEditorFramework.mts index 4732628..f871a21 100644 --- a/client/src/CodeChatEditorFramework.mts +++ b/client/src/CodeChatEditorFramework.mts @@ -17,7 +17,7 @@ // `CodeChatEditorFramework.mts` -- the CodeChat Editor Client Framework // ===================================================================== // -// This maintains a websocket connection between the CodeChat Editor Server. The +// This maintains a websocket connection with the CodeChat Editor Server. The // accompanying HTML is a full-screen iframe, allowing the Framework to change // or update the webpage in response to messages received from the websocket, or // to report navigation events to as a websocket message when the iframe's @@ -40,7 +40,7 @@ import { KeysOfRustEnum, MessageResult, UpdateMessageContents, -} from "./shared_types.mjs"; +} from "./shared.mjs"; import { console_log, on_error, @@ -207,6 +207,7 @@ class WebSocketComm { contents, current_update.is_re_translation, current_update.cursor_position, + current_update.scroll_position, ); } else { // If the page is still loading, wait until the @@ -285,8 +286,7 @@ class WebSocketComm { // `pending_messages`. const pending_message = this.pending_messages[id]; if (pending_message !== undefined) { - const { timer_id, callback } = - this.pending_messages[id]; + const { timer_id, callback } = pending_message; clearTimeout(timer_id); callback(); delete this.pending_messages[id]; @@ -523,7 +523,7 @@ export const format_struct = (complex_data_structure: any): string => /*eslint-disable-next-line @typescript-eslint/no-explicit-any */ const report_error = (text: string, ...objs: any) => { console.error(text); - if (objs !== undefined) { + if (objs.length > 0) { console.log(...objs); } show_toast(text); diff --git a/client/src/CodeMirror-integration.mts b/client/src/CodeMirror-integration.mts index cebefbb..fa076ab 100644 --- a/client/src/CodeMirror-integration.mts +++ b/client/src/CodeMirror-integration.mts @@ -82,6 +82,12 @@ import { python } from "@codemirror/lang-python"; import { rust } from "@codemirror/lang-rust"; import { sql } from "@codemirror/lang-sql"; import { yaml } from "@codemirror/lang-yaml"; +import { StreamLanguage } from "@codemirror/language"; +import { shell } from "@codemirror/legacy-modes/mode/shell"; +import { swift } from "@codemirror/legacy-modes/mode/swift"; +import { toml } from "@codemirror/legacy-modes/mode/toml"; +import { verilog } from "@codemirror/legacy-modes/mode/verilog"; +import { vhdl } from "@codemirror/legacy-modes/mode/vhdl"; import { tinymce, init } from "./tinymce-config.mjs"; import { Editor, EditorEvent, Events } from "tinymce"; @@ -99,7 +105,7 @@ import { CodeMirrorDocBlockTuple, StringDiff, UpdateMessageContents, -} from "./shared_types.mjs"; +} from "./shared.mjs"; import { assert } from "./assert.mjs"; import { show_toast } from "./show_toast.mjs"; @@ -179,7 +185,7 @@ export const docBlockField = StateField.define({ for (const effect of tr.effects) if (effect.is(addDocBlock)) { // Check that we're not overwriting text. - const newlines = current_view.state.doc + const newlines = tr.newDoc .slice(effect.value.from, effect.value.to) .toString(); if (newlines !== "\n".repeat(newlines.length)) { @@ -202,7 +208,7 @@ export const docBlockField = StateField.define({ widget: new DocBlockWidget( effect.value.indent, effect.value.delimiter, - effect.value.content, + effect.value.contents, false, ), ...decorationOptions, @@ -262,9 +268,7 @@ export const docBlockField = StateField.define({ to = effect.value.to ?? to; const from = effect.value.from_new ?? effect.value.from; // Check that we're not overwriting text. - const newlines = current_view.state.doc - .slice(from, to) - .toString(); + const newlines = tr.newDoc.slice(from, to).toString(); if (newlines !== "\n".repeat(newlines.length)) { report_error(`Attempt to overwrite text: "${newlines}".`); window.close(); @@ -309,11 +313,12 @@ export const docBlockField = StateField.define({ return doc_blocks; }, - // [Provide](https://codemirror.net/docs/ref/#state.StateField^define^config.provide) - // extensions based on this field. See also + // Register this `DecorationSet` as a source of decorations for the editor + // view — without it, the `StateField` holds the data but nothing tells + // CodeMirror to render the doc block widgets. See + // [Provide](https://codemirror.net/docs/ref/#state.StateField^define^config.provide), // [EditorView.decorations](https://codemirror.net/docs/ref/#view.EditorView^decorations) - // and [from](https://codemirror.net/docs/ref/#state.Facet.from). TODO: I - // don't understand what this does, but removing it breaks the extension. + // and [from](https://codemirror.net/docs/ref/#state.Facet.from). provide: (field: StateField) => EditorView.decorations.from(field), @@ -323,12 +328,18 @@ export const docBlockField = StateField.define({ // contents (including these doc blocks) to JSON, which can then be sent // back to the server for reassembly into a source file. toJSON: (value: DecorationSet, _state: EditorState) => { - const json = []; + const json_result = []; for (const iter = value.iter(); iter.value !== null; iter.next()) { const w = iter.value.spec.widget; - json.push([iter.from, iter.to, w.indent, w.delimiter, w.contents]); + json_result.push([ + iter.from, + iter.to, + w.indent, + w.delimiter, + w.contents, + ]); } - return json; + return json_result; }, // For loading a file from the server back into the editor, use @@ -368,9 +379,9 @@ export const addDocBlock = StateEffect.define<{ to: number; indent: string; delimiter: string; - content: string; + contents: string; }>({ - map: ({ from, to, indent, delimiter, content }, change: ChangeDesc) => ({ + map: ({ from, to, indent, delimiter, contents }, change: ChangeDesc) => ({ // Update the location (from/to) of this effect due to the transaction's // changes. See this // [thread](https://discuss.codemirror.net/t/mapping-ranges-in-a-decoration/9307/3). @@ -378,7 +389,7 @@ export const addDocBlock = StateEffect.define<{ to: change.mapPos(to), indent, delimiter, - content, + contents, }), }); @@ -436,8 +447,9 @@ class DocBlockWidget extends WidgetType { readonly contents: string, readonly is_user_change: boolean, ) { - // TODO: I don't understand why I don't need to store the provided - // parameters in the object: `this.indent = indent;`, etc. + // [Typescript parameter properties](https://www.typescriptlang.org/docs/handbook/2/classes.html#parameter-properties) + // means these parameters are automatically promoted to class + // properties. super(); } @@ -459,9 +471,9 @@ class DocBlockWidget extends WidgetType { // pasting whitespace. `

` + + )}>${sanitize_html(this.indent)}` + // The contents of this doc block. - `
` + + `
` + this.contents + "
"; // TODO: this is an async call. However, CodeMirror doesn't provide @@ -480,12 +492,14 @@ class DocBlockWidget extends WidgetType { if (this.is_user_change) { return true; } - (dom.childNodes[0] as HTMLDivElement).innerHTML = this.indent; + (dom.childNodes[0] as HTMLDivElement).innerHTML = sanitize_html( + this.indent, + ); // The contents div could be a TinyMCE instance, or just a plain div. // Handle both cases. const [contents_div, is_tinymce] = get_contents(dom); - window.MathJax.typesetClear(contents_div); + window.MathJax.typesetClear([contents_div]); if (is_tinymce) { // Save the cursor location before the update, then restore it // afterwards, if TinyMCE has focus. @@ -532,6 +546,13 @@ class DocBlockWidget extends WidgetType { } } +// Native DOM sanitizer. +const sanitize_html = (html: string) => { + const div = document.createElement("div"); + div.textContent = html; + return div.innerHTML; +}; + // Typeset the provided node; taken from the // [MathJax docs](https://docs.mathjax.org/en/latest/web/typeset.html#handling-asynchronous-typesetting). export const mathJaxTypeset = async ( @@ -597,6 +618,11 @@ const element_is_in_doc_block = ( // lead to nasty bugs at some point. // 4. When an HTML doc block is assigned to the TinyMCE instance for editing, // the dirty flag is set. This must be ignored. +// +// Potential bug: race condition. If one doc block is modified and schedules +// on\_dirty, but then another doc block is modified, then modifications to the +// first doc block would be lost. However, I doubt the user can switch doc +// blocks this fast. const on_dirty = ( // The div that's dirty. It must be a child of the doc block div. event_target: HTMLElement, @@ -648,7 +674,7 @@ const on_dirty = ( }); }; -// Handle cursur movement and mouse selection in a doc block. +// Handle cursor movement and mouse selection in a doc block. export const DocBlockPlugin = ViewPlugin.fromClass( class { constructor(_view: EditorView) {} @@ -767,8 +793,8 @@ export const DocBlockPlugin = ViewPlugin.fromClass( setTimeout(async () => { // Before untypesetting, make sure all other typesets // finish. - await new Promise((resolve) => - window.MathJax.whenReady(resolve(undefined)), + await new Promise((resolve) => + window.MathJax.whenReady(() => resolve()), ); // Untypeset math in the old doc block and the current // doc block before moving its contents around. @@ -786,7 +812,7 @@ export const DocBlockPlugin = ViewPlugin.fromClass( // // Copy the current TinyMCE instance contents into a // contenteditable div. - const old_contents_div = document.createElement("div")!; + const old_contents_div = document.createElement("div"); old_contents_div.className = "CodeChat-doc-contents"; old_contents_div.contentEditable = "true"; old_contents_div.innerHTML = @@ -865,7 +891,7 @@ const autosaveExtension = EditorView.updateListener.of( let isChanged = v.docChanged; // Look for changes to doc blocks as well; skip if a change was already // detected for efficiency. - if (!v.docChanged && v.transactions?.length) { + if (!v.docChanged && v.transactions.length) { // Check each effect of each transaction. outer: for (const tr of v.transactions) { for (const effect of tr.effects) { @@ -926,9 +952,9 @@ export const CodeMirror_load = async ( let parser; // TODO: dynamically load the parser. switch (codechat_for_web.metadata.mode) { - // Languages with a parser + // Languages with a parser. case "sh": - parser = cpp(); + parser = StreamLanguage.define(shell); break; case "cpp": parser = cpp(); @@ -960,32 +986,36 @@ export const CodeMirror_load = async ( case "sql": parser = sql(); break; + case "swift": + parser = StreamLanguage.define(swift); + break; + case "toml": + parser = StreamLanguage.define(toml); + break; case "typescript": parser = javascript({ typescript: true }); break; + case "vhdl": + parser = StreamLanguage.define(vhdl); + break; + case "verilog": + parser = StreamLanguage.define(verilog); + break; case "yaml": parser = yaml(); break; // Languages without a parser. + // + // JSON5 allows comments, but JSON doesn't. case "json5": parser = json(); break; + // Nothing available. Python isn't even close. case "matlab": parser = python(); break; - case "swift": - parser = python(); - break; - case "toml": - parser = json(); - break; - case "vhdl": - parser = cpp(); - break; - case "verilog": - parser = cpp(); - break; + // An approximation for Vlang. case "v": parser = javascript(); break; @@ -1088,7 +1118,7 @@ export const CodeMirror_load = async ( to: add[1], indent: add[2], delimiter: add[3], - content: add[4], + contents: add[4], }), ); } else if ("Update" in transaction) { diff --git a/client/src/HashReader.mts b/client/src/HashReader.mts index b62ecf5..7d78cdd 100644 --- a/client/src/HashReader.mts +++ b/client/src/HashReader.mts @@ -59,7 +59,8 @@ interface Metafile { }; } -// Load the esbuild metafile. +// Load the esbuild metafile. This must always be run from the `client/` +// directory. const data = await fs.readFile("meta.json", { encoding: "utf8" }); // Interpret it as JSON. @@ -68,36 +69,37 @@ const metafile: Metafile = JSON.parse(data); // Walk the file, looking for the names of specific entry points. Transform // those into paths used to import these files. const outputContents: Record = {}; -let num_found = 0; +let numFound = 0; for (const output in metafile.outputs) { const outputInfo = metafile.outputs[output]; switch (outputInfo.entryPoint) { case "src/CodeChatEditorFramework.mts": outputContents["CodeChatEditorFramework.js"] = output; - ++num_found; + ++numFound; break; case "src/CodeChatEditor.mts": outputContents["CodeChatEditor.js"] = output; outputContents["CodeChatEditor.css"] = outputInfo.cssBundle!; - ++num_found; + ++numFound; break; case "src/CodeChatEditor-test.mts": outputContents["CodeChatEditor-test.js"] = output; outputContents["CodeChatEditor-test.css"] = outputInfo.cssBundle!; - ++num_found; + ++numFound; break; case "src/css/CodeChatEditorProject.css": outputContents["CodeChatEditorProject.css"] = output; - ++num_found; + ++numFound; break; } } -console.assert(num_found === 4); - +if (numFound !== 4) { + throw new Error(`Expected 4 entry points, found ${numFound}`); +} // Write this to disk. await fs.writeFile( "../server/hashLocations.json", diff --git a/client/src/shared_types.mts b/client/src/shared.mts similarity index 91% rename from client/src/shared_types.mts rename to client/src/shared.mts index 1f003cb..334fc34 100644 --- a/client/src/shared_types.mts +++ b/client/src/shared.mts @@ -14,7 +14,7 @@ // the CodeChat Editor. If not, see // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). // -// `shared_types.mts` -- Shared type definitions +// `shared.mts` -- Shared definitions // ============================================= // // The time, in ms, to wait between the last user edit and sending updated data @@ -22,11 +22,11 @@ export const autosave_timeout_ms = 300; // Produce a whole random number. Fractional numbers aren't consistently -// converted to the same number. Note that the mantissa of a JavaScript `Number` +// converted to the same number across JavaScript and Rust. Note that the mantissa of a JavaScript `Number` // is 53 bits per the // [docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#number_encoding). -// To be certain, also round the result. -export const rand = () => Math.round(Math.random() * 2 ** 53); +// To be certain, also floor the result. +export const rand = () => Math.floor(Math.random() * 2 ** 53); // ### Message types // diff --git a/client/src/show_toast.mts b/client/src/show_toast.mts index 461a4d4..e1b48e0 100644 --- a/client/src/show_toast.mts +++ b/client/src/show_toast.mts @@ -25,6 +25,7 @@ export const show_toast = (text: string) => duration: 10000, newWindow: true, close: true, + escapeMarkup: true, gravity: "top", position: "right", stopOnFocus: true, diff --git a/extensions/VSCode/src/extension.ts b/extensions/VSCode/src/extension.ts index 1f2cc70..808de9b 100644 --- a/extensions/VSCode/src/extension.ts +++ b/extensions/VSCode/src/extension.ts @@ -46,7 +46,7 @@ import { MessageResult, rand, UpdateMessageContents, -} from "../../../client/src/shared_types.mjs"; +} from "../../../client/src/shared.mjs"; import { DEBUG_ENABLED, MAX_MESSAGE_LENGTH, @@ -417,7 +417,9 @@ export const activate = (context: vscode.ExtensionContext) => { const editor = get_text_editor(doc); const scroll_line = current_update.scroll_position; if (scroll_line !== undefined && editor) { - ignore_selection_change = true; + // Don't set `ignore_scroll_position` here, + // since `revealRange` doesn't change the + // editor's text selection. const scroll_position = new vscode.Position( // The VSCode line is zero-based; the // CodeMirror line is one-based. @@ -450,6 +452,7 @@ export const activate = (context: vscode.ExtensionContext) => { cursor_position, ), ]; + ignore_selection_change = false; } await sendResult(id); break; @@ -522,9 +525,7 @@ export const activate = (context: vscode.ExtensionContext) => { // Report if this was an error. const result_contents = value as MessageResult; if ("Err" in result_contents) { - const err = result_contents[ - "Err" - ] as ResultErrTypes; + const err = result_contents["Err"]; if ( err instanceof Object && "OutOfSync" in err @@ -535,11 +536,10 @@ export const activate = (context: vscode.ExtensionContext) => { ); send_update(true); } else { - // If the client is out of sync, re-sync it. - if (result_contents) - show_error( - `Error in message ${id}: ${JSON.stringify(err)}`, - ); + // Report the error. + show_error( + `Error in message ${id}: ${JSON.stringify(err)}`, + ); } } break; @@ -662,7 +662,7 @@ const send_update = (this_is_dirty: boolean) => { // the user to rapidly cycle through several editors without // needing to reload the Client with each cycle. current_editor = ate; - const current_file = ate!.document.fileName; + const current_file = ate.document.fileName; console_log( `CodeChat Editor extension: sending CurrentFile(${current_file}}).`, ); diff --git a/extensions/VSCode/src/lib.rs b/extensions/VSCode/src/lib.rs index a0108dd..ceec586 100644 --- a/extensions/VSCode/src/lib.rs +++ b/extensions/VSCode/src/lib.rs @@ -89,7 +89,8 @@ impl CodeChatEditorServer { pub async fn send_message_update_plain( &self, file_path: String, - // `null` to send no source code; a string to send the source code. + // `null` to send no source code; a `(string, version)` to send the + // source code. option_contents: Option<(String, f64)>, cursor_position: Option, scroll_position: Option, diff --git a/server/src/ide.rs b/server/src/ide.rs index 50e87dc..b609b44 100644 --- a/server/src/ide.rs +++ b/server/src/ide.rs @@ -13,8 +13,24 @@ // You should have received a copy of the GNU General Public License along with // the CodeChat Editor. If not, see // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). -/// `ide.rs` -- Provide interfaces with common IDEs -/// =============================================== +//! `ide.rs` -- Provide interfaces with common IDEs +//! =============================================== +//! +//! This module bridges IDE extensions and the CodeChat Editor's core server. +//! Its central type, `CodeChatEditorServer`, starts the Actix web server in a +//! dedicated OS thread (isolating its async runtime from the IDE's own runtime) +//! and exposes a typed message-passing interface for the extension to use: +//! +//! - **`send_message_*`** methods push editor events (file opened, file +//! changed, cursor moved, …) into the server's translation pipeline. +//! - **`get_message`** / **`get_message_timeout`** retrieve responses from the +//! server (including synthetic timeout errors for unacknowledged messages). +//! - **`stop_server`** gracefully shuts the server down. +//! +//! All internal fields are private so that IDE extensions are forced to use +//! only this public interface, hiding the implementation details of the server. +//! Sub-modules (`filewatcher` — file watcher support, `vscode`) contain +//! IDE-specific logic. pub mod filewatcher; pub mod vscode; @@ -87,6 +103,7 @@ pub struct CodeChatEditorServer { } impl CodeChatEditorServer { + // Creating the server could fail, so this must return an `io::Result`. pub fn new() -> std::io::Result { // Start the server. let (server, app_state) = setup_server( @@ -100,11 +117,8 @@ impl CodeChatEditorServer { let connection_id_raw = random::().to_string(); let connection_id = connection_id_raw_to_str(&connection_id_raw); let app_state_task = app_state.clone(); - let translation_queues = create_translation_queues( - connection_id_raw_to_str(connection_id_raw.as_str()), - &app_state, - ) - .map_err(|err| std::io::Error::other(format!("Unable to create queues: {err}")))?; + let translation_queues = create_translation_queues(connection_id.clone(), &app_state) + .map_err(|err| std::io::Error::other(format!("Unable to create queues: {err}")))?; thread::spawn(move || { start_server( connection_id_raw, @@ -177,7 +191,7 @@ impl CodeChatEditorServer { } // Send the provided message contents; add in an ID and add this to the list - // of pending messages. This produces a timeout of a matching `Result` + // of pending messages. This produces a timeout if a matching `Result` // message isn't received with the timeout. async fn send_message_timeout( &self, @@ -262,6 +276,8 @@ impl CodeChatEditorServer { is_re_translation: false, contents: option_contents.map(|contents| CodeChatForWeb { metadata: SourceFileMetadata { + // The IDE doesn't need to provide the `mode`; this will + // determined by the server. mode: "".to_string(), }, source: CodeMirrorDiffable::Plain(CodeMirror { @@ -308,11 +324,11 @@ impl CodeChatEditorServer { // This returns after the server shuts down. pub async fn stop_server(&self) { self.server_handle.stop(true).await; - // Stop all running timers. + // Since the server is closing, don't report any expired message. + self.expired_messages_rx.lock().await.close(); + // Stop all running timers, now that no new messages will arrive. for (_id, join_handle) in self.pending_messages.lock().await.drain() { join_handle.abort(); } - // Since the server is closing, don't report any expired message. - self.expired_messages_rx.lock().await.close(); } } diff --git a/server/src/ide/filewatcher.rs b/server/src/ide/filewatcher.rs index 7e8d3c0..72abcf8 100644 --- a/server/src/ide/filewatcher.rs +++ b/server/src/ide/filewatcher.rs @@ -319,7 +319,8 @@ pub fn get_logical_drive() -> Result, std::io::Error> { let mut mask = 1; let mut result: Vec = vec![]; - for index in 1..26 { + // Recall that the range 1..27 ends a 26, covering all drive letters. + for index in 1..27 { if mask & bitmask == mask { let char = std::char::from_u32(index + 64); result.push(char.unwrap()); @@ -400,7 +401,7 @@ async fn processing_task( match app_state.ide_queues.lock().unwrap().remove(&connection_id) { Some(queues) => (queues.from_websocket_tx.clone(), queues.to_websocket_rx), None => { - let err = "No websocket queues for connection id {connection_id}."; + let err = format!("No websocket queues for connection id {connection_id}."); error!("{err}"); return Err(error::ErrorBadRequest(err)); } @@ -589,11 +590,12 @@ async fn processing_task( let result = 'process: { // Check that the file path matches the current // file. If `canonicalize` fails, then the files - // don't match. + // don't match. Note that `file_path` is already + // canonicalized. if Some(Path::new(&update_message_contents.file_path).to_path_buf()) != current_filepath { break 'process Err(ResultErrTypes::WrongFileUpdate(update_message_contents.file_path, current_filepath.clone())); } - // With code or a path, there's nothing to save. + // Without code, there's nothing to save. let codechat_for_web = match update_message_contents.contents { None => break 'process Ok(ResultOkTypes::Void), Some(cfw) => cfw, @@ -633,7 +635,8 @@ async fn processing_task( { break 'err_exit Err(ResultErrTypes::FileUnwatchError(cfp.to_path_buf(), err.to_string())); } - // Update to the new path. + // Update to the new path, which is already + // canonicalized. current_filepath = Some(file_path.to_path_buf()); // Watch the new file. @@ -663,7 +666,7 @@ async fn processing_task( EditorMessageContents::LoadFile(..) => { // We never have the requested file loaded in this - // "IDE". Intead, it's always on disk. + // "IDE". Instead, it's always on disk. send_response(&from_ide_tx, m.id, Ok(ResultOkTypes::LoadFile(None))).await; } @@ -992,7 +995,10 @@ mod tests { .unwrap(); let (id_rx, msg_rx) = get_message_as!(to_client_rx, EditorMessageContents::Result); assert_eq!(id, id_rx); - matches!(cast!(&msg_rx, Err), ResultErrTypes::ClientIllegalMessage); + assert!(matches!( + cast!(&msg_rx, Err), + ResultErrTypes::ClientIllegalMessage + )); } // 5. Send an update message with no path. @@ -1008,7 +1014,7 @@ mod tests { is_re_translation: false, contents: Some(CodeChatForWeb { metadata: SourceFileMetadata { - mode: "".to_string(), + mode: "cpp".to_string(), }, source: CodeMirrorDiffable::Plain(CodeMirror { doc: "".to_string(), diff --git a/server/src/ide/vscode.rs b/server/src/ide/vscode.rs index 77a21b5..b6fa791 100644 --- a/server/src/ide/vscode.rs +++ b/server/src/ide/vscode.rs @@ -77,7 +77,7 @@ pub async fn vscode_ide_websocket( } CreateTranslationQueuesError::IdeInUse(connection_id_str) => { return client_websocket( - connection_id_str.clone(), + connection_id_str, req, body, app_state.ide_queues.clone(), @@ -126,10 +126,9 @@ pub fn vscode_ide_core( // Make sure it's the `Opened` message. let EditorMessageContents::Opened(ide_type) = first_message.message else { - let id = first_message.id; let err = ResultErrTypes::UnexpectedMessage(format!("{:#?}", first_message)); error!("{err}"); - send_response(&to_ide_tx, id, Err(err)).await; + send_response(&to_ide_tx, first_message.id, Err(err)).await; // Send a `Closed` message to shut down the websocket. queue_send!(to_ide_tx.send(EditorMessage { id: RESERVED_MESSAGE_ID, message: EditorMessageContents::Closed}), 'task); @@ -156,8 +155,8 @@ pub fn vscode_ide_core( first_message.id ); send_response(&to_ide_tx, first_message.id, Ok(ResultOkTypes::Void)).await; - - // Send the HTML for the internal browser. + // Send the HTML for the internal browser. The ID of + // this message is `RESERVED_MESSAGE_ID`. let client_html = formatdoc!( r#" @@ -195,7 +194,7 @@ pub fn vscode_ide_core( Ok(()) } else { Err(format!( - "Unexpected message LoadFile contents {result_ok:?}." + "Unexpected Result message with LoadFile contents {result_ok:?}." )) } }, @@ -204,7 +203,8 @@ pub fn vscode_ide_core( }; if let Err(err) = res { error!("{err}"); - // Send a `Closed` message. + // Send a `Closed` message using the next available + // ID (`RESERVED_MESSAGE_ID + 1`). queue_send!(to_ide_tx.send(EditorMessage { id: RESERVED_MESSAGE_ID + 1.0, message: EditorMessageContents::Closed @@ -220,7 +220,9 @@ pub fn vscode_ide_core( error!("{err:?}"); send_response(&to_ide_tx, first_message.id, Err(err)).await; - // Send a `Closed` message. + // Send a `Closed` message; use an ID of + // `RESERVED_MESSAGE_ID`, since this is the first + // message from the IDE. queue_send!(to_ide_tx.send(EditorMessage{ id: RESERVED_MESSAGE_ID, message: EditorMessageContents::Closed @@ -237,7 +239,8 @@ pub fn vscode_ide_core( error!("{err:?}"); send_response(&to_ide_tx, first_message.id, Err(err)).await; - // Close the connection. + // Close the connection, again using the first available ID + // of `RESERVED_MESSAGE_ID`. queue_send!(to_ide_tx.send(EditorMessage { id: RESERVED_MESSAGE_ID, message: EditorMessageContents::Closed}), 'task); break 'task; } diff --git a/server/src/ide/vscode/tests.rs b/server/src/ide/vscode/tests.rs index 1670608..bf431a5 100644 --- a/server/src/ide/vscode/tests.rs +++ b/server/src/ide/vscode/tests.rs @@ -64,7 +64,7 @@ use crate::{ }; use test_utils::{ cast, - test_utils::{_prep_test_dir, check_logger_errors, configure_testing_logger}, + test_utils::{check_logger_errors, configure_testing_logger, prep_test_dir_impl}, }; // Globals @@ -197,7 +197,7 @@ async fn _prep_test( test_full_name: &str, ) -> (TempDir, PathBuf, WebSocketStreamTcp, WebSocketStreamTcp) { configure_testing_logger(); - let (temp_dir, test_dir) = _prep_test_dir(test_full_name); + let (temp_dir, test_dir) = prep_test_dir_impl(test_full_name); // Ensure the webserver is running. let _ = &*WEBSERVER_HANDLE; let now = SystemTime::now(); diff --git a/server/src/lexer.rs b/server/src/lexer.rs index c261cf7..1be1dda 100644 --- a/server/src/lexer.rs +++ b/server/src/lexer.rs @@ -49,7 +49,7 @@ use supported_languages::get_language_lexer_vec; /// so, must newlines be escaped? /// * It defines heredocs in a flexible form (see `HeredocDelim` for more /// details). -/// * It associates an Ace mode and filename extensions with the lexer. +/// * It associates a CodeMirror mode and filename extensions with the lexer. /// /// This lexer ignores line continuation characters; in C/C++/Python, it's a `\` /// character followed immediately by a newline @@ -59,7 +59,7 @@ use supported_languages::get_language_lexer_vec; /// /// 1. It would allow the lexer to recognize the following C/C++ snippet as a /// doc block: `// This is an odd\` `two-line inline comment.` However, this -/// such such unusual syntax (most authors would instead use either a block +/// is such unusual syntax (most authors would instead use either a block /// comment or another inline comment) that recognizing it adds little value. /// 2. I'm unaware of any valid syntax in which ignoring a line continuation /// would cause the lexer to mis-recognize code as a comment. (Escaped @@ -185,7 +185,7 @@ pub struct LanguageLexersCompiled { pub language_lexer_compiled_vec: Vec>, // Maps a file extension to indices into the lexers vector. pub map_ext_to_lexer_vec: HashMap, Vec>>, - // Maps an Ace mode to an index into the lexers vector. + // Maps a CodeMirror mode to an index into the lexers vector. pub map_mode_to_lexer: HashMap, Arc>, } @@ -323,7 +323,7 @@ fn build_lexer_regex( let mut regex_builder = |// // An array of alternative delimiters, which will // be combined with a regex or (`|`) operator. - string_arr: &Vec, + string_arr: &[String], // The type of delimiter in `string_arr`. regex_delim_type: RegexDelimType| { // If there are no delimiters, then there's nothing to do. @@ -339,11 +339,9 @@ fn build_lexer_regex( // Add the opening block comment delimiter to the overall regex; add the // closing block comment delimiter to the map for the corresponding group. - let mut block_comment_opening_delim: Vec = vec!["".to_string()]; for block_comment_delim in &language_lexer.block_comment_delim_arr { - block_comment_opening_delim[0].clone_from(&block_comment_delim.opening); regex_builder( - &block_comment_opening_delim, + std::slice::from_ref(&block_comment_delim.opening), // Determine the block closing regex: RegexDelimType::BlockComment( Regex::new(&if block_comment_delim.is_nestable { @@ -363,7 +361,7 @@ fn build_lexer_regex( ); } regex_builder( - &language_lexer.inline_comment_delim_arr.to_vec(), + &language_lexer.inline_comment_delim_arr, RegexDelimType::InlineComment, ); // Build regexes for each string delimiter. @@ -494,7 +492,7 @@ fn build_lexer_regex( } .unwrap(); regex_builder( - &[regex::escape(&string_delim_spec.delimiter)].to_vec(), + std::slice::from_ref(&string_delim_spec.delimiter), RegexDelimType::String(end_of_string_regex), ); } @@ -504,7 +502,7 @@ fn build_lexer_regex( // A C# verbatim string has asymmetric opening and closing delimiters, // making it a special case. SpecialCase::CSharpVerbatimStringLiteral => regex_builder( - &vec!["@\"".to_string()], + &["@\"".to_string()], RegexDelimType::String(Regex::new(C_SHARP_VERBATIM_STRING_CLOSING).unwrap()), ), SpecialCase::TemplateLiteral => { @@ -519,7 +517,7 @@ fn build_lexer_regex( // // TODO: match either an unescaped `${` -- which causes a nested // parse -- or the closing backtick (which must be unescaped). - regex_builder(&vec!["`".to_string()], RegexDelimType::TemplateLiteral); + regex_builder(&["`".to_string()], RegexDelimType::TemplateLiteral); } SpecialCase::Matlab => { // MATLAB supports block comments, when the comment delimiters @@ -687,6 +685,10 @@ pub fn source_lexer( // Provide a method to intelligently append to the code/doc block vec. Empty // appends are ignored; appends of the same type append to `contents` // instead of creating a new entry. + // + // See if we have a PEG-based parser for this language; use that if + // available. This parser normalizes line endings on its own, so don't + // normalize here. if let Some(parser) = language_lexer_compiled.language_lexer.parser { return parser(source_code); } @@ -1011,15 +1013,13 @@ pub fn source_lexer( // strings/heredocs, in particular) until we leave the // nested comment block. Therefore, keep track of the // nesting depth; when this returns to 0, we've found - // outermost closing block comment delimiter, and can - // return to normal parsing. At this point in the code, - // we've found one opening block comment delimiter, so - // the nesting depth starts at 1. - let mut nesting_depth = 1; - let mut loop_count = 0; + // the outermost closing block comment delimiter, and + // can return to normal parsing. At this point in the + // code, we've found one opening block comment + // delimiter, so the nesting depth starts at 1. + let mut nesting_depth: u32 = 1; // Loop until we've outside all nested block comments. - while nesting_depth != 0 && loop_count < 10 { - loop_count += 1; + while nesting_depth != 0 { // Get the index of the next block comment // delimiter. #[cfg(feature = "lexer_explain")] @@ -1079,7 +1079,7 @@ pub fn source_lexer( opening_delimiter.start(), opening_delimiter.len() ); - source_code_unlexed_index += + source_code_unlexed_index = comment_start_index + opening_delimiter.start(); comment_start_index = source_code_unlexed_index + opening_delimiter.len(); @@ -1091,8 +1091,8 @@ pub fn source_lexer( continue; } else { // This is a closing comment delimiter. + assert!(nesting_depth > 0); nesting_depth -= 1; - assert!(nesting_depth >= 0); let closing_delimiter_match = if delimiter_captures.len() == 3 { delimiter_captures.get(2).unwrap() } else { @@ -1103,10 +1103,9 @@ pub fn source_lexer( // then mark this text as code and continue the // loop. if !last_delimiter_was_opening { - source_code_unlexed_index += comment_start_index + source_code_unlexed_index = comment_start_index + closing_delimiter_match.start() + closing_delimiter_match.len(); - last_delimiter_was_opening = false; #[cfg(feature = "lexer_explain")] println!( "Found a non-innermost closing block comment delimiter. Nesting depth: {}", @@ -1114,6 +1113,12 @@ pub fn source_lexer( ); continue; } + // Now that we've used this variable to + // determine that the current comment is a doc + // block, update it: this is a closing + // delimited, so the last delimiter for the next + // iteration is not an opening delimiter. + last_delimiter_was_opening = false; // Otherwise, this is a potential doc block: // it's an innermost nested block comment. See diff --git a/server/src/lexer/pest/c.pest b/server/src/lexer/pest/c.pest index 51f4a3a..0cebf31 100644 --- a/server/src/lexer/pest/c.pest +++ b/server/src/lexer/pest/c.pest @@ -67,7 +67,7 @@ block_comment_closing_delim_2 = { unused } // [hard line break](https://spec.commonmark.org/0.31.2/#hard-line-breaks) in // Markdown, which means inserting a hard line break this way in an inline // comment requires the next line to omit the inline comment delimiters. For -// example:  +// example: // // ```C // // This is a hard line break\ diff --git a/server/src/lexer/pest_parser.rs b/server/src/lexer/pest_parser.rs index f3c0c53..5924706 100644 --- a/server/src/lexer/pest_parser.rs +++ b/server/src/lexer/pest_parser.rs @@ -26,7 +26,7 @@ // // ### Third-party // -// None. +// None. Though note that each parser module has local third-party imports. // // ### Local // @@ -36,8 +36,8 @@ /// /// This macro generates a parser function that converts the provided string /// into a series of code and doc blocks. I'd prefer to use traits, but don't -/// see a way to pass the `Rule` types as a usable. (Using `RuleType` means we -/// can't access `Rule::file`, etc.) +/// see a way to pass the `Rule` types as a parameter. (Using `RuleType` means +/// we can't access `Rule::file`, etc.) #[macro_export] macro_rules! make_parse_to_code_doc_blocks { ($parser: ty) => { @@ -48,7 +48,7 @@ macro_rules! make_parse_to_code_doc_blocks { // CodeMirror indexes work. let normalized_input = &String::from_iter(normalize_line_endings::normalized(input.chars())); - let pairs = match <$parser>::parse(Rule::file, normalized_input) { + let mut pairs = match <$parser>::parse(Rule::file, normalized_input) { Ok(pairs) => pairs, Err(e) => panic!("Parse error: {e:#?}"), } @@ -63,10 +63,8 @@ macro_rules! make_parse_to_code_doc_blocks { assert_eq!(pairs.clone().last().unwrap().as_rule(), Rule::EOI); // Transform these tokens into code and doc blocks; ignore the last // token (EOI). + pairs.next_back(); pairs - .rev() - .skip(1) - .rev() .map(|block| match block.as_rule() { Rule::inline_comment => { // Gather all tokens in the inline comment. @@ -76,15 +74,14 @@ macro_rules! make_parse_to_code_doc_blocks { let whitespace = whitespace_pair.as_str(); let inline_comment_delim = inline_comment.next().unwrap(); // Combine the text of all the inline comments. - let comment = &mut inline_comment.fold( - String::new(), - |mut acc, inline_comment_body| { + let comment = + &inline_comment.fold(String::new(), |mut acc, inline_comment_body| { assert_eq!( inline_comment_body.as_rule(), Rule::inline_comment_line ); let s = inline_comment_body.as_str(); - let inner = &mut inline_comment_body.into_inner(); + let mut inner = inline_comment_body.into_inner(); // See the notes on inline comments in // [c.pest](pest/c.pest) for the expected // structure of the `inline_comment_body`. @@ -103,8 +100,7 @@ macro_rules! make_parse_to_code_doc_blocks { // comment contents) to the accumulator. acc.push_str(contents); acc - }, - ); + }); // Determine which opening delimiter was used. let _delimiter_index = match inline_comment_delim.as_rule() { @@ -130,7 +126,7 @@ macro_rules! make_parse_to_code_doc_blocks { let pre_whitespace_pair = block_comment.next().unwrap(); assert_eq!(pre_whitespace_pair.as_rule(), Rule::white_space); let pre_whitespace = pre_whitespace_pair.as_str(); - let block_comment_opening_delim = block_comment.next().unwrap().as_rule(); + let block_comment_opening_delim = block_comment.next().unwrap(); let block_comment_pre_pair = block_comment.next().unwrap(); assert_eq!(block_comment_pre_pair.as_rule(), Rule::block_comment_pre); let block_comment_pre = block_comment_pre_pair.as_str(); @@ -167,13 +163,6 @@ macro_rules! make_parse_to_code_doc_blocks { let block_comment_ending = block_comment_ending_pair.as_str(); assert!(block_comment.next().is_none()); - // Determine which opening delimiter was used. - let _opening_delim_index = match block_comment_opening_delim { - Rule::block_comment_opening_delim_0 => 0, - Rule::block_comment_opening_delim_1 => 1, - Rule::block_comment_opening_delim_2 => 2, - _ => unreachable!(), - }; // TODO -- use this in the future. //println!("Opening delimiter index: {}", opening_delim_index); @@ -197,7 +186,9 @@ macro_rules! make_parse_to_code_doc_blocks { let mut full_comment = parse_block_comment(&pre_whitespace, &full_comment); // Trim the optional space, if it exists. if !optional_space.is_empty() && full_comment.ends_with(optional_space) { - full_comment.pop(); + // Don't `pop()`, in case the space is a multi-byte + // character is some bizarre grammar. + full_comment.truncate(full_comment.len() - optional_space.len()); } // Transform this to a doc block. @@ -205,7 +196,7 @@ macro_rules! make_parse_to_code_doc_blocks { let lines = full_comment.lines().count(); $crate::lexer::CodeDocBlock::DocBlock($crate::lexer::DocBlock { indent: pre_whitespace.to_string(), - delimiter: "/*".to_string(), + delimiter: block_comment_opening_delim.to_string(), contents: full_comment.to_string(), lines, }) diff --git a/server/src/lexer/supported_languages.rs b/server/src/lexer/supported_languages.rs index f0c27a6..1097ee1 100644 --- a/server/src/lexer/supported_languages.rs +++ b/server/src/lexer/supported_languages.rs @@ -31,8 +31,9 @@ /// then if that's not found, the single quote. A regex of `"|"""` would never /// match the triple quote, since the single quote would match first. /// -/// Note that the lexers here should be complemented by the appropriate Ace mode -/// in [ace-webpack.mts](../../../client/src/ace-webpack.mts). +/// Note that the lexers here should be complemented by the appropriate +/// CodeMirror mode in +/// [CodeMirror-integration.mts](../../../client/src/CodeMirror-integration.mts). /// /// ###
String delimiter doubling /// @@ -182,19 +183,23 @@ pub fn get_language_lexer_vec() -> Vec { // [6.3.3 Comments](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/lexical-structure#633-comments). // Also provide support for // [documentation comments](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/documentation-comments). - &["//", "///"], + &["///", "//"], &[ - make_block_comment_delim("/*", "*/", false), make_block_comment_delim("/**", "*/", false), + make_block_comment_delim("/*", "*/", false), ], &[make_string_delimiter_spec( // See // [6.4.5.6 String literals](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/lexical-structure#6456-string-literals). + // This should also handle interpolated string literals. "\"", "\\", NewlineSupport::None, )], + // TODO: support + // [C# 11 raw string literals](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/raw-string). None, + // This also handles interpolated verbatim string literals. SpecialCase::CSharpVerbatimStringLiteral, None, ), @@ -219,7 +224,7 @@ pub fn get_language_lexer_vec() -> Vec { // See // [The Go Programming Language Specification](https://go.dev/ref/spec) // on [Comments](https://go.dev/ref/spec#Comments). - &[], + &["//"], &[make_block_comment_delim("/*", "*/", false)], // See [String literals](https://go.dev/ref/spec#String_literals). &[ @@ -237,8 +242,8 @@ pub fn get_language_lexer_vec() -> Vec { &[], &[make_block_comment_delim("", false)], &[ - make_string_delimiter_spec("\"", "\\", NewlineSupport::Unescaped), - make_string_delimiter_spec("'", "\\", NewlineSupport::Unescaped), + make_string_delimiter_spec("\"", "", NewlineSupport::Unescaped), + make_string_delimiter_spec("'", "", NewlineSupport::Unescaped), ], None, SpecialCase::None, @@ -259,17 +264,17 @@ pub fn get_language_lexer_vec() -> Vec { // See // [§3.10.5. String Literals](https://docs.oracle.com/javase/specs/jls/se19/html/jls-3.html#jls-3.10.5). &[ + // See + // [§3.10.6. Text Blocks](https://docs.oracle.com/javase/specs/jls/se19/html/jls-3.html#jls-3.10.6). + make_string_delimiter_spec("\"\"\"", "\\", NewlineSupport::Unescaped), make_string_delimiter_spec( "\"", "\\", - // Per the previous link, It is a compile-time error for - // a line terminator (§3.4) to appear after the opening " - // and before the matching closing "." + // Per §3.10.5, It is a compile-time error for a line + // terminator (§3.4) to appear after the opening " and + // before the matching closing "." NewlineSupport::None, ), - // See - // [§3.10.6. Text Blocks](https://docs.oracle.com/javase/specs/jls/se19/html/jls-3.html#jls-3.10.6). - make_string_delimiter_spec("\"\"\"", "\\", NewlineSupport::Unescaped), ], None, SpecialCase::None, @@ -370,7 +375,7 @@ pub fn get_language_lexer_vec() -> Vec { ], // Likewise, raw byte strings behave identically to raw strings from // this lexer's perspective. - make_heredoc_delim("r", "#+", "\"", "\"", ""), + make_heredoc_delim("r", "#*", "\"", "\"", ""), SpecialCase::None, None, ), @@ -446,7 +451,7 @@ pub fn get_language_lexer_vec() -> Vec { // Basic strings make_string_delimiter_spec("\"", "\\", NewlineSupport::None), // Literal strings - make_string_delimiter_spec("'", "\\", NewlineSupport::Escaped), + make_string_delimiter_spec("'", "", NewlineSupport::None), ], None, SpecialCase::None, @@ -459,8 +464,8 @@ pub fn get_language_lexer_vec() -> Vec { &["//"], &[make_block_comment_delim("/*", "*/", false)], &[ - make_string_delimiter_spec("\"", "\\", NewlineSupport::Unescaped), - make_string_delimiter_spec("'", "\\", NewlineSupport::Unescaped), + make_string_delimiter_spec("\"", "\\", NewlineSupport::Escaped), + make_string_delimiter_spec("'", "\\", NewlineSupport::Escaped), ], None, SpecialCase::TemplateLiteral, @@ -501,8 +506,10 @@ pub fn get_language_lexer_vec() -> Vec { ), // ### [V](https://vlang.io/) make_language_lexer( - // Ace doesn't support V yet. - "", + // CodeMirror doesn't support V yet. Go ahead and include a name for + // the future. + "v", + // Note that this overlaps with Verilog. &["v"], // See // [Comments](https://github.com/vlang/v/blob/master/doc/docs.md#comments). diff --git a/server/src/lexer/tests.rs b/server/src/lexer/tests.rs index b9ea6d8..266f3e7 100644 --- a/server/src/lexer/tests.rs +++ b/server/src/lexer/tests.rs @@ -590,19 +590,28 @@ fn test_rust() { assert_eq!( source_lexer( - r#"/* Depth 1 + r#" /* Depth 1 /* Depth 2 comment */ /* Depth 2 /* Depth 3 */ */ + /* Depth 2 + /* Depth 3 comment */ + */ More depth 1 */"#, rust ), [ - build_code_block("/* Depth 1\n"), + build_code_block(" /* Depth 1\n"), build_doc_block(" ", "/*", "Depth 2 comment\n"), build_code_block( r#" /* Depth 2 /* Depth 3 */ */ + /* Depth 2 +"# + ), + build_doc_block(" ", "/*", "Depth 3 comment\n"), + build_code_block( + r#" */ More depth 1 */"# ), ] diff --git a/server/src/main.rs b/server/src/main.rs index ec00937..bc44303 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -13,8 +13,19 @@ // You should have received a copy of the GNU General Public License along with // the CodeChat Editor. If not, see // [http://www.gnu.org/licenses](http://www.gnu.org/licenses). -/// `main.rs` -- Entrypoint for the CodeChat Editor Server -/// ====================================================== +//! `main.rs` -- Entrypoint for the CodeChat Editor Server +//! ====================================================== +//! +//! This file implements the command-line interface (CLI) for the CodeChat +//! Editor server binary. It provides three subcommands: +//! +//! - `serve`: Start the webserver in the foreground. +//! - `start`: Spawn the webserver as a background child process, polling +//! until it responds to a ping, then optionally open a browser. +//! - `stop`: Send a stop request to a running server instance. +//! +//! All subcommands accept `--host` and `--port` options to control the +//! server's network address. // Imports // ------- // @@ -22,7 +33,7 @@ use std::{ env, fs, io::{self, Read}, - net::{IpAddr, Ipv4Addr, SocketAddr}, + net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, ops::RangeInclusive, path::PathBuf, process::{Child, Command, Stdio}, @@ -80,7 +91,7 @@ enum Commands { log: Option, /// Define the username:password used to limit access to the server. By - /// default, access is unlimited. + /// default, access is unlimited. The username may not contain a colon.- #[arg(short, long, value_parser = parse_credentials)] auth: Option, }, @@ -116,8 +127,7 @@ impl Cli { addr, credentials.clone(), log.unwrap_or(LevelFilter::Info), - ) - .unwrap(); + )?; } Commands::Start { open } => { // Poll the server to ensure it starts. @@ -321,24 +331,23 @@ fn port_in_range(s: &str) -> Result { } fn parse_credentials(s: &str) -> Result { - let split_: Vec<_> = s.split(":").collect(); - if split_.len() != 2 { - Err(format!( - "Unable to parse credentials as username:password; found {} colon-separated string(s), but expected 2", - split_.len() - )) - } else { - Ok(Credentials { - username: split_[0].to_string(), - password: split_[1].to_string(), - }) - } + // For simplicity, require a username to have no colons. + let split: Vec<_> = s.splitn(2, ":").collect(); + Ok(Credentials { + username: split[0].to_string(), + password: split[1].to_string(), + }) } +/// This is used by `ping` to transform the "access connections from any address" address into localhost, a valid destination address for a ping. fn fix_addr(addr: &SocketAddr) -> SocketAddr { if addr.ip() == IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)) { let mut addr = *addr; - addr.set_ip(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))); + addr.set_ip(IpAddr::V4(Ipv4Addr::LOCALHOST)); + addr + } else if addr.ip() == IpAddr::V6(Ipv6Addr::UNSPECIFIED) { + let mut addr = *addr; + addr.set_ip(IpAddr::V6(Ipv6Addr::LOCALHOST)); addr } else { *addr @@ -356,7 +365,7 @@ fn main() -> Result<(), Box> { #[tokio::main] async fn get_server_url(port: u16) -> Result { - return code_chat_editor::webserver::get_server_url(port).await; + code_chat_editor::webserver::get_server_url(port).await } #[cfg(test)] diff --git a/server/src/processing.rs b/server/src/processing.rs index 403cd05..dcb2ecc 100644 --- a/server/src/processing.rs +++ b/server/src/processing.rs @@ -456,7 +456,7 @@ pub fn codechat_for_web_to_source( .map_err(CodechatForWebToSourceError::CannotTranslateCodeChat) } -/// Return the byte index of `s[u16_16_index]`, where the indexing operation is +/// Return the byte index of `s[utf_16_index]`, where the indexing operation is /// in UTF-16 code units. fn byte_index_of(s: &str, utf_16_index: usize) -> usize { let mut byte_index = 0; @@ -648,7 +648,7 @@ pub enum CodeDocBlockVecToSourceError { // Turn this vec of CodeDocBlocks into a string of source code. fn code_doc_block_vec_to_source( - code_doc_block_vec: &Vec, + code_doc_block_vec: &[CodeDocBlock], lexer: &LanguageLexerCompiled, ) -> Result { let mut file_contents = String::new(); @@ -884,7 +884,7 @@ pub fn source_to_codechat_for_web( // Walk through the code/doc blocks, ... let doc_contents = code_doc_block_arr .iter() - // ...selcting only the doc block contents... + // ...selecting only the doc block contents... .filter_map(|cdb| { if let CodeDocBlock::DocBlock(db) = cdb { Some(db.contents.as_str()) @@ -910,21 +910,21 @@ pub fn source_to_codechat_for_web( // 3. Hydrate the cleaned HTML. let html = hydrate_html(&html) .map_err(|e| SourceToCodeChatForWebError::ParseFailed(e.to_string()))?; - // 3. Split on the separator. + // 4. Split on the separator. let mut doc_block_contents_iter = html.split(DOC_BLOCK_SEPARATOR_SPLIT_STRING); // // Translate each `CodeDocBlock` to its `CodeMirror` equivalent. + let mut len = len_utf16(&code_mirror.doc); for code_or_doc_block in code_doc_block_arr { let source = &mut code_mirror.doc; match code_or_doc_block { - CodeDocBlock::CodeBlock(code_string) => source.push_str(&code_string), + CodeDocBlock::CodeBlock(code_string) => { + source.push_str(&code_string); + len += len_utf16(&code_string) + } CodeDocBlock::DocBlock(doc_block) => { // Create the doc block. - // - // Get the length of the string in characters (not - // bytes, which is what `len()` returns). - let len = source.chars().count(); code_mirror.doc_blocks.push(CodeMirrorDocBlock { from: len, // To. Note that the last doc block could be zero @@ -940,6 +940,7 @@ pub fn source_to_codechat_for_web( // replace these in the editor. This keeps the line // numbering of non-doc blocks correct. source.push_str(&"\n".repeat(doc_block.lines)); + len += doc_block.lines; } } } @@ -950,6 +951,11 @@ pub fn source_to_codechat_for_web( Ok(TranslationResults::CodeChat(codechat_for_web)) } +// Compute the length of the provided string in UTF16 characters. +fn len_utf16(s: &str) -> usize { + s.chars().map(|c| c.len_utf16()).sum() +} + // Like `source_to_codechat_for_web`, translate a source file to the CodeChat // Editor client format. This wraps a call to that function with additional // processing (determine if this is part of a project, encode the output as @@ -1304,7 +1310,7 @@ static CUSTOM_ELEMENT_TO_CODE_BLOCK_LANGUAGE: phf::Map<&'static str, &'static st // this approach is to modify only what changed, rather than changing // everything. As a secondary goal, this hopefully improves overall performance // by sending less data between the server and the client, in spite of the -// additional computational requirements for compting the diff. +// additional computational requirements for computing the diff. // // Fundamentally, diffs of a string and diff of this vector require different // approaches: @@ -1480,7 +1486,7 @@ pub fn diff_code_mirror_doc_blocks( &prev_after_range_start_val.delimiter, ), contents: diff_str( - &prev_after_range_start_val.contents, + &prev_before_range_start_val.contents, &prev_after_range_start_val.contents, ), }, @@ -1587,15 +1593,10 @@ pub fn diff_code_mirror_doc_blocks( let mut immediate_sequence_start_index: Option = None; for index in 0..change_specs.len() { let is_add = matches!(&change_specs[index], CodeMirrorDocBlockTransaction::Add(_)); - let is_inserted_update = if let CodeMirrorDocBlockTransaction::Update(update) = - &change_specs[index] - && let Some(from_new) = update.from_new - && from_new > update.from - { - true - } else { - false - }; + let is_inserted_update = matches!( + &change_specs[index], + CodeMirrorDocBlockTransaction::Update(u) if u.from_new.is_some_and(|f| f > u.from) + ); if is_add || is_inserted_update { // This is an update produced by inserting lines. if immediate_sequence_start_index.is_none() { diff --git a/server/src/processing/tests.rs b/server/src/processing/tests.rs index f47c1a8..d54f384 100644 --- a/server/src/processing/tests.rs +++ b/server/src/processing/tests.rs @@ -288,64 +288,57 @@ fn test_code_doc_blocks_to_source_py() { let py_lexer = llc.map_mode_to_lexer.get(&stringit("python")).unwrap(); // An empty document. - assert_eq!(code_doc_block_vec_to_source(&vec![], py_lexer).unwrap(), ""); + assert_eq!(code_doc_block_vec_to_source(&[], py_lexer).unwrap(), ""); // A one-line comment. assert_eq!( - code_doc_block_vec_to_source(&vec![build_doc_block("", "#", "Test")], py_lexer).unwrap(), + code_doc_block_vec_to_source(&[build_doc_block("", "#", "Test")], py_lexer).unwrap(), "# Test" ); assert_eq!( - code_doc_block_vec_to_source(&vec![build_doc_block("", "#", "Test\n")], py_lexer).unwrap(), + code_doc_block_vec_to_source(&[build_doc_block("", "#", "Test\n")], py_lexer).unwrap(), "# Test\n" ); // Check empty doc block lines and multiple lines. assert_eq!( - code_doc_block_vec_to_source( - &vec![build_doc_block("", "#", "Test 1\n\nTest 2")], - py_lexer - ) - .unwrap(), + code_doc_block_vec_to_source(&[build_doc_block("", "#", "Test 1\n\nTest 2")], py_lexer) + .unwrap(), "# Test 1\n#\n# Test 2" ); // Repeat the above tests with an indent. assert_eq!( - code_doc_block_vec_to_source(&vec![build_doc_block(" ", "#", "Test")], py_lexer).unwrap(), + code_doc_block_vec_to_source(&[build_doc_block(" ", "#", "Test")], py_lexer).unwrap(), " # Test" ); assert_eq!( - code_doc_block_vec_to_source(&vec![build_doc_block(" ", "#", "Test\n")], py_lexer) - .unwrap(), + code_doc_block_vec_to_source(&[build_doc_block(" ", "#", "Test\n")], py_lexer).unwrap(), " # Test\n" ); assert_eq!( - code_doc_block_vec_to_source( - &vec![build_doc_block(" ", "#", "Test 1\n\nTest 2")], - py_lexer - ) - .unwrap(), + code_doc_block_vec_to_source(&[build_doc_block(" ", "#", "Test 1\n\nTest 2")], py_lexer) + .unwrap(), " # Test 1\n #\n # Test 2" ); // Basic code. assert_eq!( - code_doc_block_vec_to_source(&vec![build_code_block("Test")], py_lexer).unwrap(), + code_doc_block_vec_to_source(&[build_code_block("Test")], py_lexer).unwrap(), "Test" ); // An incorrect delimiter. assert_eq!( - code_doc_block_vec_to_source(&vec![build_doc_block("", "?", "Test")], py_lexer), + code_doc_block_vec_to_source(&[build_doc_block("", "?", "Test")], py_lexer), Err(CodeDocBlockVecToSourceError::UnknownCommentOpeningDelimiter("?".to_string())) ); // Empty doc blocks separated by an empty code block. assert_eq!( code_doc_block_vec_to_source( - &vec![ + &[ build_doc_block("", "#", "\n"), build_code_block("\n"), - build_doc_block("", "#", ""), + build_doc_block("", "#", "") ], py_lexer ) @@ -355,10 +348,10 @@ fn test_code_doc_blocks_to_source_py() { assert_eq!( code_doc_block_vec_to_source( - &vec![ + &[ build_doc_block("", "#", "σ\n"), build_code_block("σ\n"), - build_doc_block("", "#", "σ"), + build_doc_block("", "#", "σ") ], py_lexer ) @@ -375,24 +368,20 @@ fn test_code_doc_blocks_to_source_css() { let css_lexer = llc.map_mode_to_lexer.get(&stringit("css")).unwrap(); // An empty document. - assert_eq!( - code_doc_block_vec_to_source(&vec![], css_lexer).unwrap(), - "" - ); + assert_eq!(code_doc_block_vec_to_source(&[], css_lexer).unwrap(), ""); // A one-line comment. assert_eq!( - code_doc_block_vec_to_source(&vec![build_doc_block("", "/*", "Test\n")], css_lexer) - .unwrap(), + code_doc_block_vec_to_source(&[build_doc_block("", "/*", "Test\n")], css_lexer).unwrap(), "/* Test */\n" ); assert_eq!( - code_doc_block_vec_to_source(&vec![build_doc_block("", "/*", "Test")], css_lexer).unwrap(), + code_doc_block_vec_to_source(&[build_doc_block("", "/*", "Test")], css_lexer).unwrap(), "/* Test */" ); // Check empty doc block lines and multiple lines. assert_eq!( code_doc_block_vec_to_source( - &vec![ + &[ build_code_block("Test_0\n"), build_doc_block("", "/*", "Test 1\n\nTest 2\n") ], @@ -408,13 +397,12 @@ fn test_code_doc_blocks_to_source_css() { // Repeat the above tests with an indent. assert_eq!( - code_doc_block_vec_to_source(&vec![build_doc_block(" ", "/*", "Test\n")], css_lexer) - .unwrap(), + code_doc_block_vec_to_source(&[build_doc_block(" ", "/*", "Test\n")], css_lexer).unwrap(), " /* Test */\n" ); assert_eq!( code_doc_block_vec_to_source( - &vec![ + &[ build_code_block("Test_0\n"), build_doc_block(" ", "/*", "Test 1\n\nTest 2\n") ], @@ -430,13 +418,13 @@ fn test_code_doc_blocks_to_source_css() { // Basic code. assert_eq!( - code_doc_block_vec_to_source(&vec![build_code_block("Test")], css_lexer).unwrap(), + code_doc_block_vec_to_source(&[build_code_block("Test")], css_lexer).unwrap(), "Test" ); // An incorrect delimiter. assert_eq!( - code_doc_block_vec_to_source(&vec![build_doc_block("", "?", "Test")], css_lexer), + code_doc_block_vec_to_source(&[build_doc_block("", "?", "Test")], css_lexer), Err(CodeDocBlockVecToSourceError::UnknownCommentOpeningDelimiter("?".to_string())) ); } @@ -448,37 +436,32 @@ fn test_code_doc_blocks_to_source_csharp() { let csharp_lexer = llc.map_mode_to_lexer.get(&stringit("csharp")).unwrap(); // An empty document. - assert_eq!( - code_doc_block_vec_to_source(&vec![], csharp_lexer).unwrap(), - "" - ); + assert_eq!(code_doc_block_vec_to_source(&[], csharp_lexer).unwrap(), ""); // An invalid comment. assert_eq!( - code_doc_block_vec_to_source(&vec![build_doc_block("", "?", "Test\n")], csharp_lexer), + code_doc_block_vec_to_source(&[build_doc_block("", "?", "Test\n")], csharp_lexer), Err(CodeDocBlockVecToSourceError::UnknownCommentOpeningDelimiter("?".to_string())) ); // Inline comments. assert_eq!( - code_doc_block_vec_to_source(&vec![build_doc_block("", "//", "Test\n")], csharp_lexer) - .unwrap(), + code_doc_block_vec_to_source(&[build_doc_block("", "//", "Test\n")], csharp_lexer).unwrap(), "// Test\n" ); assert_eq!( - code_doc_block_vec_to_source(&vec![build_doc_block("", "///", "Test\n")], csharp_lexer) + code_doc_block_vec_to_source(&[build_doc_block("", "///", "Test\n")], csharp_lexer) .unwrap(), "/// Test\n" ); // Block comments. assert_eq!( - code_doc_block_vec_to_source(&vec![build_doc_block("", "/*", "Test\n")], csharp_lexer) - .unwrap(), + code_doc_block_vec_to_source(&[build_doc_block("", "/*", "Test\n")], csharp_lexer).unwrap(), "/* Test */\n" ); assert_eq!( - code_doc_block_vec_to_source(&vec![build_doc_block("", "/**", "Test\n")], csharp_lexer) + code_doc_block_vec_to_source(&[build_doc_block("", "/**", "Test\n")], csharp_lexer) .unwrap(), "/** Test */\n" ); @@ -644,23 +627,48 @@ fn test_source_to_codechat_for_web_1() { ))) ); - // Test Unicode characters in code. + // Test Unicode characters and multi-byte Unicode characters in code. + // + // ``` + // \u03c3 \ud83d \ude04 \ud83d \udc49 \ud83c \udfff \ud83d \udc68 \u200d \ud83d \udc66 \ud83c \uddfa \ud83c \uddf3 + // index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // char: --σ-- ---😄--- ----------👉🏿--------- --------------👨‍👦-------------- -----------🇺🇳---------- + // ``` + // + // These are taken from the [MDN UTF-16 + // docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#utf-16_characters_unicode_code_points_and_grapheme_clusters). assert_eq!( - source_to_codechat_for_web("; // σ\n//", &"cpp".to_string(), 0.0, false, false), + source_to_codechat_for_web("; // σ😄👉🏿👨‍👦🇺🇳\n//", &"cpp".to_string(), 0.0, false, false), Ok(TranslationResults::CodeChat(build_codechat_for_web( "cpp", - "; // σ\n", - vec![build_codemirror_doc_block(7, 8, "", "//", ""),] + "; // σ😄👉🏿👨‍👦🇺🇳\n", + vec![build_codemirror_doc_block(22, 23, "", "//", ""),] ))) ); - // Test Unicode characters in strings. + // Test Unicode characters and multi-byte Unicode characters in strings. assert_eq!( - source_to_codechat_for_web("\"σ\";\n//", &"cpp".to_string(), 0.0, false, false), + source_to_codechat_for_web("\"σ😄👉🏿👨‍👦🇺🇳\";\n//", &"cpp".to_string(), 0.0, false, false), Ok(TranslationResults::CodeChat(build_codechat_for_web( "cpp", - "\"σ\";\n", - vec![build_codemirror_doc_block(5, 6, "", "//", ""),] + "\"σ😄👉🏿👨‍👦🇺🇳\";\n", + vec![build_codemirror_doc_block(20, 21, "", "//", ""),] + ))) + ); + + // Test Unicode characters and multi-byte Unicode characters in comments. + assert_eq!( + source_to_codechat_for_web("// σ😄👉🏿👨‍👦🇺🇳\n;", &"cpp".to_string(), 0.0, false, false), + Ok(TranslationResults::CodeChat(build_codechat_for_web( + "cpp", + "\n;", + vec![build_codemirror_doc_block( + 0, + 1, + "", + "//", + "

σ😄👉🏿👨‍👦🇺🇳

\n" + ),] ))) ); diff --git a/server/src/translation.rs b/server/src/translation.rs index 01c29e6..5bbf590 100644 --- a/server/src/translation.rs +++ b/server/src/translation.rs @@ -305,10 +305,9 @@ pub fn create_translation_queues( // // 1. It hasn't been used before. In this case, create the appropriate // queues and start websocket and processing tasks. - // 2. It's in use, but was disconnected. In this case, re-use the queues and - // start the websocket task; the processing task is still running. - // 3. It's in use by another IDE. This is an error, but I don't have a way - // to detect it yet. + // 2. It's in use, but was disconnected. Return this as an error; the caller + // can resume the connection if appropriate. + // 3. It's in use by another IDE. Return this as an error. // // Check case 3. if app_state @@ -424,12 +423,12 @@ struct TranslationTask { /// Therefore, assign each file a version number. All files are sent with a /// unique, randomly-generated version number which define the file's /// version after this update is applied. Diffs also include the version - /// number of the file before applying the diff; the - // receiver's current version number must match with the sender's - /// pre-diff version number in order to apply the diff. When the versions - /// don't match, the IDE must send a full text file to the Server and Client - /// to re-sync. When a file is first loaded, its version number is None, - /// signaling that the sender must always provide the full text, not a diff. + /// number of the file before applying the diff; the receiver's current + /// version number must match with the sender's pre-diff version number in + /// order to apply the diff. When the versions don't match, the IDE must + /// send a full text file to the Server and Client to re-sync. When a file + /// is first loaded, its version number is None, signaling that the sender + /// must always provide the full text, not a diff. version: f64, /// Has the full (non-diff) version of the current file been sent? Don't /// send diffs until this is sent. @@ -455,7 +454,7 @@ pub async fn translation_task( if !shutdown_only { debug!("VSCode processing task started."); - // Create a queue for HTTP requests fo communicate with this task. + // Create a queue for HTTP requests to communicate with this task. let (from_http_tx, from_http_rx) = mpsc::channel(10); app_state .processing_task_queue_tx @@ -1204,7 +1203,9 @@ impl TranslationTask { // (Unix style). fn eol_convert(s: String, eol_type: &EolType) -> String { if eol_type == &EolType::Crlf { - s.replace("\n", "\r\n") + // There shouldn't be any Windows-style CRLFs -- but if there are, + // handle this nicely. + s.replace("\r\n", "\n").replace("\n", "\r\n") } else { s } @@ -1247,7 +1248,7 @@ fn compare_html( } } -// Given a vector of two doc blocks, compare them, ignoring newlines. +// Given vectors of two doc blocks, compare them, ignoring newlines. fn doc_block_compare(a: &CodeMirrorDocBlockVec, b: &CodeMirrorDocBlockVec) -> bool { if a.len() != b.len() { return false; diff --git a/server/src/webserver.rs b/server/src/webserver.rs index 070fe1b..b4fb389 100644 --- a/server/src/webserver.rs +++ b/server/src/webserver.rs @@ -508,9 +508,7 @@ lazy_static! { |err| panic!("Error: Unable to read {:#?}: {err}", hl.to_string_lossy()) ); let hmm: HashMap = - serde_json::from_str(&json).expect( - &format!("Unable to parse JSON in {:#?}", hl.to_string_lossy()) - ); + serde_json::from_str(&json).unwrap_or_else(|_| panic!("Unable to parse JSON in {:#?}", hl.to_string_lossy())); hmm }; @@ -966,7 +964,7 @@ pub async fn file_to_response( {name} - The CodeChat Editor {MATHJAX_TAGS} - +
@@ -1010,7 +1008,7 @@ pub async fn file_to_response( {name} - The CodeChat Editor {MATHJAX_TAGS} - + {sidebar_css} diff --git a/test_utils/src/test_macros.rs b/test_utils/src/test_macros.rs index 1df3d2e..3253eb5 100644 --- a/test_utils/src/test_macros.rs +++ b/test_utils/src/test_macros.rs @@ -31,7 +31,7 @@ macro_rules! cast { // For an enum containing a single value (the typical case). ($target: expr, $pat: path) => {{ - // The `if let` exploits recent Rust compiler's smart pattern matching. + // The `if let` exploits the Rust compiler's smart pattern matching. // Contrary to other solutions like `into_variant` and friends, this one // macro covers all ownership usage like `self`, `&self` and `&mut // self`. On the other hand `{into,as,as_mut}_{variant}` solution @@ -52,7 +52,11 @@ macro_rules! cast { if let $pat($($tup,)*) = $target { ($($tup,)*) } else { - panic!("mismatch variant when cast to {}", stringify!($pat)); + panic!( + "mismatch variant when cast to {} with values {}", + stringify!($pat), + stringify!($tup) + ); } }}; } @@ -62,23 +66,13 @@ macro_rules! cast { #[macro_export] macro_rules! function_name { () => {{ - fn f() {} - fn type_name_of(_: T) -> &'static str { + const fn f() {} + const fn type_name_of(_: T) -> &'static str { std::any::type_name::() } let name = type_name_of(f); - // Since we just called the nested function f, strip this off the end of + // Since we just called the nested function `f``, strip this off the end of // the returned value. name.strip_suffix("::f").unwrap() }}; } - -// Call `_prep_test_dir` with the correct parameter -- `function_name!()`. -#[macro_export] -macro_rules! prep_test_dir { - () => {{ - use $crate::function_name; - use $crate::test_utils::_prep_test_dir; - _prep_test_dir(function_name!()) - }}; -} diff --git a/test_utils/src/test_utils.rs b/test_utils/src/test_utils.rs index 352590c..f764323 100644 --- a/test_utils/src/test_utils.rs +++ b/test_utils/src/test_utils.rs @@ -86,13 +86,13 @@ macro_rules! function_name { }}; } -// Call `_prep_test_dir` with the correct parameter -- `function_name!()`. +// Call `prep_test_dir_impl` with the correct parameter -- `function_name!()`. #[macro_export] macro_rules! prep_test_dir { () => {{ use $crate::function_name; - use $crate::test_utils::_prep_test_dir; - _prep_test_dir(function_name!()) + use $crate::test_utils::prep_test_dir_impl; + prep_test_dir_impl(function_name!()) }}; } @@ -103,14 +103,14 @@ macro_rules! prep_test_dir { // store files for testing. A subdirectory tree, named by the module path then // name of the test function by convention, contains everything needed for this // test. Copy this over to a temporary directory, then run tests there. -pub fn _prep_test_dir( +pub fn prep_test_dir_impl( // The name of and Rust path to the test function to prepare files for. Call // `prep_test_dir!()` to provide this parameter. test_full_name: &str, ) -> ( // The temporary directory created which stores files to use in testing. TempDir, - // The + // The directory which contains copied test fixture files. PathBuf, ) { // Get rid of closures in the path. @@ -183,7 +183,7 @@ pub fn check_logger_errors(num_expected_errors: usize) { assert_le!( error_logs.len(), num_expected_errors, - "Error(s) in logs: saw {}, expected {num_expected_errors}.", + "Error(s) in logs: saw {}, expected {num_expected_errors} or fewer.", error_logs.len() ); }); diff --git a/test_utils/src/testing_logger.rs b/test_utils/src/testing_logger.rs index 94ba23d..4389b9a 100644 --- a/test_utils/src/testing_logger.rs +++ b/test_utils/src/testing_logger.rs @@ -42,7 +42,7 @@ //! Log events are captured in a thread\_local variable so this module behaves //! correctly when tests are run multithreaded. //! -//! All log levels are captured, but none are sent to any logging system. The +//! All debug and higher log levels are captured, but none are sent to any logging system. The //! test developer should use the `validate()` function in order to check the //! captured log messages. //! @@ -114,15 +114,14 @@ thread_local!(static LOG_RECORDS: RefCell> = RefCell::new(Vec:: struct TestingLogger {} impl Log for TestingLogger { - #[allow(unused_variables)] - fn enabled(&self, metadata: &Metadata) -> bool { + fn enabled(&self, _metadata: &Metadata) -> bool { true // capture all log levels } fn log(&self, record: &Record) { LOG_RECORDS.with(|records| { let captured_record = CapturedLog { - body: format!("{}", record.args()), + body: record.args().to_string(), level: record.level(), target: record.target().to_string(), }; @@ -151,7 +150,7 @@ pub fn setup() { .unwrap(); }); LOG_RECORDS.with(|records| { - records.borrow_mut().truncate(0); + records.borrow_mut().clear(); }); } @@ -161,10 +160,10 @@ pub fn setup() { /// captured log events. As a side effect, the records are cleared. pub fn validate(asserter: F) where - F: Fn(&Vec), + F: Fn(&[CapturedLog]), { LOG_RECORDS.with(|records| { asserter(&records.borrow()); - records.borrow_mut().truncate(0); + records.borrow_mut().clear(); }); } diff --git a/toc.md b/toc.md index 3ba2d6f..4c39fde 100644 --- a/toc.md +++ b/toc.md @@ -54,7 +54,7 @@ Implementation * [tinymce-config.mts](client/src/tinymce-config.mts) * [graphviz-webcomponent-setup.mjs](client/src/graphviz-webcomponent-setup.mjs) * [Mermaid](client/src/third-party/wc-mermaid/developer.md) - * [shared\_types.mts](client/src/shared_types.mts) + * [shared.mts](client/src/shared.mts) * [assert.mts](client/src/assert.mts) * [show\_toast.mts](client/src/show_toast.mts) * [global.d.ts](client/src/global.d.ts) From 88d89577b9c3a5e1306bac805df8942cfaa6d948 Mon Sep 17 00:00:00 2001 From: "Bryan A. Jones" Date: Tue, 14 Apr 2026 17:50:57 +0500 Subject: [PATCH 8/9] Freeze for release. --- builder/Cargo.lock | 4 +- client/package.json5 | 2 +- client/pnpm-lock.yaml | 273 ++++++++++++++++--------------- extensions/VSCode/Cargo.lock | 135 ++++++++------- extensions/VSCode/Cargo.toml | 2 +- extensions/VSCode/package.json | 12 +- extensions/VSCode/pnpm-lock.yaml | 267 +++++++++++++++--------------- server/Cargo.lock | 192 ++++++++++++---------- server/Cargo.toml | 2 +- 9 files changed, 468 insertions(+), 421 deletions(-) diff --git a/builder/Cargo.lock b/builder/Cargo.lock index 5ae5210..20cb234 100644 --- a/builder/Cargo.lock +++ b/builder/Cargo.lock @@ -234,9 +234,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.184" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "log" diff --git a/client/package.json5 b/client/package.json5 index fd03274..389c80a 100644 --- a/client/package.json5 +++ b/client/package.json5 @@ -43,7 +43,7 @@ url: 'https://github.com/bjones1/CodeChat_editor', }, type: 'module', - version: '0.1.52', + version: '0.1.53', dependencies: { '@codemirror/commands': '^6.10.3', '@codemirror/lang-cpp': '^6.0.3', diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml index 001e9a4..947d96a 100644 --- a/client/pnpm-lock.yaml +++ b/client/pnpm-lock.yaml @@ -53,6 +53,12 @@ importers: '@codemirror/lang-yaml': specifier: ^6.1.3 version: 6.1.3 + '@codemirror/language': + specifier: ^6.12.3 + version: 6.12.3 + '@codemirror/legacy-modes': + specifier: ^6.5.2 + version: 6.5.2 '@codemirror/state': specifier: ^6.6.0 version: 6.6.0 @@ -106,11 +112,11 @@ importers: specifier: ^1.12.4 version: 1.12.4 '@typescript-eslint/eslint-plugin': - specifier: ^8.58.1 - version: 8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2) + specifier: ^8.58.2 + version: 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2) '@typescript-eslint/parser': - specifier: ^8.58.1 - version: 8.58.1(eslint@10.2.0)(typescript@6.0.2) + specifier: ^8.58.2 + version: 8.58.2(eslint@10.2.0)(typescript@6.0.2) chai: specifier: ^6.2.2 version: 6.2.2 @@ -125,28 +131,28 @@ importers: version: 10.1.8(eslint@10.2.0) eslint-plugin-import: specifier: ^2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0) + version: 2.32.0(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0) eslint-plugin-prettier: specifier: ^5.5.5 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@10.2.0))(eslint@10.2.0)(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@10.2.0))(eslint@10.2.0)(prettier@3.8.2) globals: - specifier: ^17.4.0 - version: 17.4.0 + specifier: ^17.5.0 + version: 17.5.0 mocha: specifier: ^11.7.5 version: 11.7.5 npm-check-updates: - specifier: ^20.0.0 - version: 20.0.0 + specifier: ^20.0.2 + version: 20.0.2 prettier: - specifier: ^3.8.1 - version: 3.8.1 + specifier: ^3.8.2 + version: 3.8.2 typescript: specifier: ^6.0.2 version: 6.0.2 typescript-eslint: - specifier: ^8.58.1 - version: 8.58.1(eslint@10.2.0)(typescript@6.0.2) + specifier: ^8.58.2 + version: 8.58.2(eslint@10.2.0)(typescript@6.0.2) packages: @@ -222,6 +228,9 @@ packages: '@codemirror/language@6.12.3': resolution: {integrity: sha512-QwCZW6Tt1siP37Jet9Tb02Zs81TQt6qQrZR2H+eGMcFsL1zMrk2/b9CLC7/9ieP1fjIUMgviLWMmgiHoJrj+ZA==} + '@codemirror/legacy-modes@6.5.2': + resolution: {integrity: sha512-/jJbwSTazlQEDOQw2FJ8LEEKVS72pU0lx6oM54kGpL8t/NJ2Jda3CZ4pcltiKTdqYSRk3ug1B3pil1gsjA6+8Q==} + '@codemirror/lint@6.9.5': resolution: {integrity: sha512-GElsbU9G7QT9xXhpUg1zWGmftA/7jamh+7+ydKRuT0ORpWS3wOSP0yT1FOlIZa7mIJjpVPipErsyvVqB9cfTFA==} @@ -733,63 +742,63 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - '@typescript-eslint/eslint-plugin@8.58.1': - resolution: {integrity: sha512-eSkwoemjo76bdXl2MYqtxg51HNwUSkWfODUOQ3PaTLZGh9uIWWFZIjyjaJnex7wXDu+TRx+ATsnSxdN9YWfRTQ==} + '@typescript-eslint/eslint-plugin@8.58.2': + resolution: {integrity: sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.58.1 + '@typescript-eslint/parser': ^8.58.2 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.58.1': - resolution: {integrity: sha512-gGkiNMPqerb2cJSVcruigx9eHBlLG14fSdPdqMoOcBfh+vvn4iCq2C8MzUB89PrxOXk0y3GZ1yIWb9aOzL93bw==} + '@typescript-eslint/parser@8.58.2': + resolution: {integrity: sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.58.1': - resolution: {integrity: sha512-gfQ8fk6cxhtptek+/8ZIqw8YrRW5048Gug8Ts5IYcMLCw18iUgrZAEY/D7s4hkI0FxEfGakKuPK/XUMPzPxi5g==} + '@typescript-eslint/project-service@8.58.2': + resolution: {integrity: sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.58.1': - resolution: {integrity: sha512-TPYUEqJK6avLcEjumWsIuTpuYODTTDAtoMdt8ZZa93uWMTX13Nb8L5leSje1NluammvU+oI3QRr5lLXPgihX3w==} + '@typescript-eslint/scope-manager@8.58.2': + resolution: {integrity: sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.58.1': - resolution: {integrity: sha512-JAr2hOIct2Q+qk3G+8YFfqkqi7sC86uNryT+2i5HzMa2MPjw4qNFvtjnw1IiA1rP7QhNKVe21mSSLaSjwA1Olw==} + '@typescript-eslint/tsconfig-utils@8.58.2': + resolution: {integrity: sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.58.1': - resolution: {integrity: sha512-HUFxvTJVroT+0rXVJC7eD5zol6ID+Sn5npVPWoFuHGg9Ncq5Q4EYstqR+UOqaNRFXi5TYkpXXkLhoCHe3G0+7w==} + '@typescript-eslint/type-utils@8.58.2': + resolution: {integrity: sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.58.1': - resolution: {integrity: sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw==} + '@typescript-eslint/types@8.58.2': + resolution: {integrity: sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.58.1': - resolution: {integrity: sha512-w4w7WR7GHOjqqPnvAYbazq+Y5oS68b9CzasGtnd6jIeOIeKUzYzupGTB2T4LTPSv4d+WPeccbxuneTFHYgAAWg==} + '@typescript-eslint/typescript-estree@8.58.2': + resolution: {integrity: sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.58.1': - resolution: {integrity: sha512-Ln8R0tmWC7pTtLOzgJzYTXSCjJ9rDNHAqTaVONF4FEi2qwce8mD9iSOxOpLFFvWp/wBFlew0mjM1L1ihYWfBdQ==} + '@typescript-eslint/utils@8.58.2': + resolution: {integrity: sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.58.1': - resolution: {integrity: sha512-y+vH7QE8ycjoa0bWciFg7OpFcipUuem1ujhrdLtq1gByKwfbC7bPeKsiny9e0urg93DqwGcHey+bGRKCnF1nZQ==} + '@typescript-eslint/visitor-keys@8.58.2': + resolution: {integrity: sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@upsetjs/venn.js@2.0.0': @@ -870,11 +879,11 @@ packages: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} - brace-expansion@1.1.13: - resolution: {integrity: sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==} + brace-expansion@1.1.14: + resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} - brace-expansion@2.0.3: - resolution: {integrity: sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==} + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} brace-expansion@5.0.5: resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} @@ -887,8 +896,8 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} engines: {node: '>= 0.4'} call-bound@1.0.4: @@ -1175,8 +1184,8 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} - dompurify@3.3.3: - resolution: {integrity: sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==} + dompurify@3.4.0: + resolution: {integrity: sha512-nolgK9JcaUXMSmW+j1yaSvaEaoXYHwWyGJlkoCTghc97KgGDDSnpoU/PlEnw63Ah+TGKFOyY+X5LnxaWbCSfXg==} dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} @@ -1415,8 +1424,8 @@ packages: deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true - globals@17.4.0: - resolution: {integrity: sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==} + globals@17.5.0: + resolution: {integrity: sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==} engines: {node: '>=18'} globalthis@1.0.4: @@ -1718,8 +1727,8 @@ packages: node-readable-to-web-readable-stream@0.4.2: resolution: {integrity: sha512-/cMZNI34v//jUTrI+UIo4ieHAB5EZRY/+7OmXZgBxaWBMcW2tGdceIw06RFxWxrKZ5Jp3sI2i5TsRo+CBhtVLQ==} - npm-check-updates@20.0.0: - resolution: {integrity: sha512-qCs02x51irGf0okCttwv8lHEO2NxT903IJ2bKpG82kIzkm6pfT3CoWB5YIvqY/wi/DdnYRfI7eVfCYYymQgvCg==} + npm-check-updates@20.0.2: + resolution: {integrity: sha512-nvbcXiprjMOoSX0FCHC41kjpZhNFURV53KMU0MMa0U10RPHeoHpiilMg2P8g9NLSQoo0umSH77tUqHWTOH3w7A==} engines: {node: '>=20.0.0', npm: '>=8.12.1'} hasBin: true @@ -1826,8 +1835,8 @@ packages: resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==} engines: {node: '>=6.0.0'} - prettier@3.8.1: - resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + prettier@3.8.2: + resolution: {integrity: sha512-8c3mgTe0ASwWAJK+78dpviD+A8EqhndQPUBpNUIPt6+xWlIigCwfN01lWr9MAede4uqXGTEKeQWTvzb3vjia0Q==} engines: {node: '>=14'} hasBin: true @@ -2047,8 +2056,8 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} - typescript-eslint@8.58.1: - resolution: {integrity: sha512-gf6/oHChByg9HJvhMO1iBexJh12AqqTfnuxscMDOVqfJW3htsdRJI/GfPpHTTcyeB8cSTUY2JcZmVgoyPqcrDg==} + typescript-eslint@8.58.2: + resolution: {integrity: sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -2314,6 +2323,10 @@ snapshots: '@lezer/lr': 1.4.8 style-mod: 4.1.3 + '@codemirror/legacy-modes@6.5.2': + dependencies: + '@codemirror/language': 6.12.3 + '@codemirror/lint@6.9.5': dependencies: '@codemirror/state': 6.6.0 @@ -2778,14 +2791,14 @@ snapshots: '@types/trusted-types@2.0.7': optional: true - '@typescript-eslint/eslint-plugin@8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2)': + '@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.58.1(eslint@10.2.0)(typescript@6.0.2) - '@typescript-eslint/scope-manager': 8.58.1 - '@typescript-eslint/type-utils': 8.58.1(eslint@10.2.0)(typescript@6.0.2) - '@typescript-eslint/utils': 8.58.1(eslint@10.2.0)(typescript@6.0.2) - '@typescript-eslint/visitor-keys': 8.58.1 + '@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/scope-manager': 8.58.2 + '@typescript-eslint/type-utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/visitor-keys': 8.58.2 eslint: 10.2.0 ignore: 7.0.5 natural-compare: 1.4.0 @@ -2794,41 +2807,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2)': + '@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2)': dependencies: - '@typescript-eslint/scope-manager': 8.58.1 - '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.2) - '@typescript-eslint/visitor-keys': 8.58.1 + '@typescript-eslint/scope-manager': 8.58.2 + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2) + '@typescript-eslint/visitor-keys': 8.58.2 debug: 4.4.3(supports-color@8.1.1) eslint: 10.2.0 typescript: 6.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.58.1(typescript@6.0.2)': + '@typescript-eslint/project-service@8.58.2(typescript@6.0.2)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.58.1(typescript@6.0.2) - '@typescript-eslint/types': 8.58.1 + '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.2) + '@typescript-eslint/types': 8.58.2 debug: 4.4.3(supports-color@8.1.1) typescript: 6.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.58.1': + '@typescript-eslint/scope-manager@8.58.2': dependencies: - '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/visitor-keys': 8.58.1 + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/visitor-keys': 8.58.2 - '@typescript-eslint/tsconfig-utils@8.58.1(typescript@6.0.2)': + '@typescript-eslint/tsconfig-utils@8.58.2(typescript@6.0.2)': dependencies: typescript: 6.0.2 - '@typescript-eslint/type-utils@8.58.1(eslint@10.2.0)(typescript@6.0.2)': + '@typescript-eslint/type-utils@8.58.2(eslint@10.2.0)(typescript@6.0.2)': dependencies: - '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.2) - '@typescript-eslint/utils': 8.58.1(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2) + '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2) debug: 4.4.3(supports-color@8.1.1) eslint: 10.2.0 ts-api-utils: 2.5.0(typescript@6.0.2) @@ -2836,14 +2849,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.58.1': {} + '@typescript-eslint/types@8.58.2': {} - '@typescript-eslint/typescript-estree@8.58.1(typescript@6.0.2)': + '@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.2)': dependencies: - '@typescript-eslint/project-service': 8.58.1(typescript@6.0.2) - '@typescript-eslint/tsconfig-utils': 8.58.1(typescript@6.0.2) - '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/visitor-keys': 8.58.1 + '@typescript-eslint/project-service': 8.58.2(typescript@6.0.2) + '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.2) + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/visitor-keys': 8.58.2 debug: 4.4.3(supports-color@8.1.1) minimatch: 10.2.5 semver: 7.7.4 @@ -2853,20 +2866,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.58.1(eslint@10.2.0)(typescript@6.0.2)': + '@typescript-eslint/utils@8.58.2(eslint@10.2.0)(typescript@6.0.2)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0) - '@typescript-eslint/scope-manager': 8.58.1 - '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.2) + '@typescript-eslint/scope-manager': 8.58.2 + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2) eslint: 10.2.0 typescript: 6.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.58.1': + '@typescript-eslint/visitor-keys@8.58.2': dependencies: - '@typescript-eslint/types': 8.58.1 + '@typescript-eslint/types': 8.58.2 eslint-visitor-keys: 5.0.1 '@upsetjs/venn.js@2.0.0': @@ -2906,7 +2919,7 @@ snapshots: array-includes@3.1.9: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 es-abstract: 1.24.2 @@ -2917,7 +2930,7 @@ snapshots: array.prototype.findlastindex@1.2.6: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 es-abstract: 1.24.2 @@ -2927,14 +2940,14 @@ snapshots: array.prototype.flat@1.3.3: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-abstract: 1.24.2 es-shim-unscopables: 1.1.0 array.prototype.flatmap@1.3.3: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-abstract: 1.24.2 es-shim-unscopables: 1.1.0 @@ -2942,7 +2955,7 @@ snapshots: arraybuffer.prototype.slice@1.0.4: dependencies: array-buffer-byte-length: 1.0.2 - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-abstract: 1.24.2 es-errors: 1.3.0 @@ -2961,12 +2974,12 @@ snapshots: balanced-match@4.0.4: {} - brace-expansion@1.1.13: + brace-expansion@1.1.14: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.0.3: + brace-expansion@2.1.0: dependencies: balanced-match: 1.0.2 @@ -2981,7 +2994,7 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 - call-bind@1.0.8: + call-bind@1.0.9: dependencies: call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 @@ -3305,7 +3318,7 @@ snapshots: dependencies: esutils: 2.0.3 - dompurify@3.3.3: + dompurify@3.4.0: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -3326,7 +3339,7 @@ snapshots: array-buffer-byte-length: 1.0.2 arraybuffer.prototype.slice: 1.0.4 available-typed-arrays: 1.0.7 - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 data-view-buffer: 1.0.2 data-view-byte-length: 1.0.2 @@ -3448,17 +3461,17 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2))(eslint-import-resolver-node@0.3.10)(eslint@10.2.0): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint-import-resolver-node@0.3.10)(eslint@10.2.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.58.1(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.2) eslint: 10.2.0 eslint-import-resolver-node: 0.3.10 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -3469,7 +3482,7 @@ snapshots: doctrine: 2.1.0 eslint: 10.2.0 eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2))(eslint-import-resolver-node@0.3.10)(eslint@10.2.0) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint-import-resolver-node@0.3.10)(eslint@10.2.0) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -3481,16 +3494,16 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.58.1(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-prettier@5.5.5(eslint-config-prettier@10.1.8(eslint@10.2.0))(eslint@10.2.0)(prettier@3.8.1): + eslint-plugin-prettier@5.5.5(eslint-config-prettier@10.1.8(eslint@10.2.0))(eslint@10.2.0)(prettier@3.8.2): dependencies: eslint: 10.2.0 - prettier: 3.8.1 + prettier: 3.8.2 prettier-linter-helpers: 1.0.1 synckit: 0.11.12 optionalDependencies: @@ -3603,7 +3616,7 @@ snapshots: function.prototype.name@1.1.8: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 functions-have-names: 1.2.3 @@ -3653,7 +3666,7 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 - globals@17.4.0: {} + globals@17.5.0: {} globalthis@1.0.4: dependencies: @@ -3710,7 +3723,7 @@ snapshots: is-array-buffer@3.0.5: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 get-intrinsic: 1.3.0 @@ -3909,7 +3922,7 @@ snapshots: d3-sankey: 0.12.3 dagre-d3-es: 7.0.14 dayjs: 1.11.20 - dompurify: 3.3.3 + dompurify: 3.4.0 katex: 0.16.45 khroma: 2.1.0 lodash-es: 4.18.1 @@ -3925,11 +3938,11 @@ snapshots: minimatch@3.1.5: dependencies: - brace-expansion: 1.1.13 + brace-expansion: 1.1.14 minimatch@9.0.9: dependencies: - brace-expansion: 2.0.3 + brace-expansion: 2.1.0 minimist@1.2.8: {} @@ -3980,7 +3993,7 @@ snapshots: node-readable-to-web-readable-stream@0.4.2: optional: true - npm-check-updates@20.0.0: {} + npm-check-updates@20.0.2: {} object-inspect@1.13.4: {} @@ -3988,7 +4001,7 @@ snapshots: object.assign@4.1.7: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 @@ -3997,27 +4010,27 @@ snapshots: object.entries@1.1.9: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 object.fromentries@2.0.8: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-abstract: 1.24.2 es-object-atoms: 1.1.1 object.groupby@1.0.3: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-abstract: 1.24.2 object.values@1.2.1: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 @@ -4094,7 +4107,7 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier@3.8.1: {} + prettier@3.8.2: {} punycode@2.3.1: {} @@ -4106,7 +4119,7 @@ snapshots: reflect.getprototypeof@1.0.10: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-abstract: 1.24.2 es-errors: 1.3.0 @@ -4117,7 +4130,7 @@ snapshots: regexp.prototype.flags@1.5.4: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-errors: 1.3.0 get-proto: 1.0.1 @@ -4148,7 +4161,7 @@ snapshots: safe-array-concat@1.1.3: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 get-intrinsic: 1.3.0 has-symbols: 1.1.0 @@ -4254,7 +4267,7 @@ snapshots: string.prototype.trim@1.2.10: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-data-property: 1.1.4 define-properties: 1.2.1 @@ -4264,14 +4277,14 @@ snapshots: string.prototype.trimend@1.0.9: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 string.prototype.trimstart@1.0.8: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-object-atoms: 1.1.1 @@ -4341,7 +4354,7 @@ snapshots: typed-array-byte-length@1.0.3: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 for-each: 0.3.5 gopd: 1.2.0 has-proto: 1.2.0 @@ -4350,7 +4363,7 @@ snapshots: typed-array-byte-offset@1.0.4: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.8 + call-bind: 1.0.9 for-each: 0.3.5 gopd: 1.2.0 has-proto: 1.2.0 @@ -4359,19 +4372,19 @@ snapshots: typed-array-length@1.0.7: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 for-each: 0.3.5 gopd: 1.2.0 is-typed-array: 1.1.15 possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript-eslint@8.58.1(eslint@10.2.0)(typescript@6.0.2): + typescript-eslint@8.58.2(eslint@10.2.0)(typescript@6.0.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2) - '@typescript-eslint/parser': 8.58.1(eslint@10.2.0)(typescript@6.0.2) - '@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.2) - '@typescript-eslint/utils': 8.58.1(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2) + '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2) eslint: 10.2.0 typescript: 6.0.2 transitivePeerDependencies: @@ -4449,7 +4462,7 @@ snapshots: which-typed-array@1.1.20: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 for-each: 0.3.5 get-proto: 1.0.1 diff --git a/extensions/VSCode/Cargo.lock b/extensions/VSCode/Cargo.lock index 262f452..e304636 100644 --- a/extensions/VSCode/Cargo.lock +++ b/extensions/VSCode/Cargo.lock @@ -8,7 +8,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "bytes", "futures-core", "futures-sink", @@ -29,7 +29,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web", - "bitflags 2.11.0", + "bitflags 2.11.1", "bytes", "derive_more", "futures-core", @@ -53,7 +53,7 @@ dependencies = [ "actix-service", "actix-utils", "base64", - "bitflags 2.11.0", + "bitflags 2.11.1", "brotli", "bytes", "bytestring", @@ -72,7 +72,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand 0.9.2", + "rand 0.9.4", "sha1", "smallvec", "tokio", @@ -406,9 +406,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] name = "block-buffer" @@ -494,9 +494,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.59" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" dependencies = [ "find-msvc-tools", "jobserver", @@ -518,7 +518,7 @@ checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" dependencies = [ "cfg-if", "cpufeatures 0.3.0", - "rand_core 0.10.0", + "rand_core 0.10.1", ] [[package]] @@ -582,7 +582,7 @@ checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" [[package]] name = "codechat-editor-server" -version = "0.1.52" +version = "0.1.53" dependencies = [ "actix-files", "actix-http", @@ -601,6 +601,7 @@ dependencies = [ "futures-util", "htmd", "html5ever", + "htmlize", "imara-diff", "indoc", "lazy_static", @@ -617,7 +618,7 @@ dependencies = [ "pest_derive", "phf", "pulldown-cmark 0.13.3", - "rand 0.10.0", + "rand 0.10.1", "regex", "serde", "serde_json", @@ -634,7 +635,7 @@ dependencies = [ [[package]] name = "codechat-editor-vscode-extension" -version = "0.1.52" +version = "0.1.53" dependencies = [ "codechat-editor-server", "log", @@ -1161,7 +1162,7 @@ dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", - "rand_core 0.10.0", + "rand_core 0.10.1", "wasip2", "wasip3", ] @@ -1185,7 +1186,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "ignore", "walkdir", ] @@ -1222,9 +1223,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" [[package]] name = "heck" @@ -1261,6 +1262,16 @@ dependencies = [ "markup5ever", ] +[[package]] +name = "htmlize" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e815d50d9e411ba2690d730e6ec139c08260dddb756df315dbd16d01a587226" +dependencies = [ + "memchr", + "pastey", +] + [[package]] name = "http" version = "0.2.12" @@ -1472,12 +1483,12 @@ checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" [[package]] name = "indexmap" -version = "2.13.1" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "serde", "serde_core", ] @@ -1497,7 +1508,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "inotify-sys", "libc", ] @@ -1584,9 +1595,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.94" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" +checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" dependencies = [ "once_cell", "wasm-bindgen", @@ -1632,9 +1643,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.184" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "libloading" @@ -1648,9 +1659,9 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ "libc", ] @@ -1725,7 +1736,7 @@ dependencies = [ "log-mdc", "mock_instant", "parking_lot", - "rand 0.9.2", + "rand 0.9.4", "serde", "serde-value", "serde_json", @@ -1832,7 +1843,7 @@ version = "3.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb7848c221fb7bb789e02f01875287ebb1e078b92a6566a34de01ef8806e7c2b" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "ctor", "futures", "napi-build", @@ -1914,7 +1925,7 @@ version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "fsevent-sys", "inotify", "kqueue", @@ -1945,7 +1956,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] @@ -1978,7 +1989,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] @@ -1993,7 +2004,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "objc2", ] @@ -2050,6 +2061,12 @@ dependencies = [ "windows-link", ] +[[package]] +name = "pastey" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" + [[package]] name = "path-slash" version = "0.2.1" @@ -2166,9 +2183,9 @@ checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "postgres-protocol" @@ -2183,7 +2200,7 @@ dependencies = [ "hmac", "md-5", "memchr", - "rand 0.10.0", + "rand 0.10.1", "sha2 0.11.0", "stringprep", ] @@ -2282,7 +2299,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "memchr", "unicase", ] @@ -2293,7 +2310,7 @@ version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c3a14896dfa883796f1cb410461aef38810ea05f2b2c33c5aded3649095fdad" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "memchr", "pulldown-cmark-escape", "unicase", @@ -2328,9 +2345,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha", "rand_core 0.9.5", @@ -2338,13 +2355,13 @@ dependencies = [ [[package]] name = "rand" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ "chacha20", "getrandom 0.4.2", - "rand_core 0.10.0", + "rand_core 0.10.1", ] [[package]] @@ -2368,9 +2385,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "redox_syscall" @@ -2378,7 +2395,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] @@ -2437,7 +2454,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "errno", "libc", "linux-raw-sys", @@ -2925,7 +2942,7 @@ dependencies = [ "pin-project-lite", "postgres-protocol", "postgres-types", - "rand 0.10.0", + "rand 0.10.1", "socket2 0.6.3", "tokio", "tokio-util", @@ -3189,9 +3206,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.117" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" +checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" dependencies = [ "cfg-if", "once_cell", @@ -3202,9 +3219,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.117" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" +checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3212,9 +3229,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.117" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" +checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" dependencies = [ "bumpalo", "proc-macro2", @@ -3225,9 +3242,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.117" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" +checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" dependencies = [ "unicode-ident", ] @@ -3260,7 +3277,7 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "hashbrown 0.15.5", "indexmap", "semver", @@ -3268,9 +3285,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.94" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" +checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d" dependencies = [ "js-sys", "wasm-bindgen", @@ -3672,7 +3689,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.0", + "bitflags 2.11.1", "indexmap", "log", "serde", diff --git a/extensions/VSCode/Cargo.toml b/extensions/VSCode/Cargo.toml index 8d88935..aa38c4d 100644 --- a/extensions/VSCode/Cargo.toml +++ b/extensions/VSCode/Cargo.toml @@ -32,7 +32,7 @@ license = "GPL-3.0-only" name = "codechat-editor-vscode-extension" readme = "../README.md" repository = "https://github.com/bjones1/CodeChat_Editor" -version = "0.1.52" +version = "0.1.53" [lib] crate-type = ["cdylib"] diff --git a/extensions/VSCode/package.json b/extensions/VSCode/package.json index 58658b4..78393eb 100644 --- a/extensions/VSCode/package.json +++ b/extensions/VSCode/package.json @@ -41,7 +41,7 @@ "type": "git", "url": "https://github.com/bjones1/CodeChat_Editor" }, - "version": "0.1.52", + "version": "0.1.53", "activationEvents": [ "onCommand:extension.codeChatEditorActivate", "onCommand:extension.codeChatEditorDeactivate" @@ -88,8 +88,8 @@ "@types/escape-html": "^1.0.4", "@types/node": "^24.12.2", "@types/vscode": "1.61.0", - "@typescript-eslint/eslint-plugin": "^8.58.1", - "@typescript-eslint/parser": "^8.58.1", + "@typescript-eslint/eslint-plugin": "^8.58.2", + "@typescript-eslint/parser": "^8.58.2", "@vscode/vsce": "^3.7.1", "chalk": "^5.6.2", "esbuild": "^0.28.0", @@ -99,10 +99,10 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^5.5.5", "npm-run-all2": "^8.0.4", - "ovsx": "^0.10.10", - "prettier": "^3.8.1", + "ovsx": "^0.10.11", + "prettier": "^3.8.2", "typescript": "^6.0.2", - "typescript-eslint": "^8.58.1" + "typescript-eslint": "^8.58.2" }, "optionalDependencies": { "bufferutil": "^4.1.0" diff --git a/extensions/VSCode/pnpm-lock.yaml b/extensions/VSCode/pnpm-lock.yaml index 30ab0f5..3c5284f 100644 --- a/extensions/VSCode/pnpm-lock.yaml +++ b/extensions/VSCode/pnpm-lock.yaml @@ -37,11 +37,11 @@ importers: specifier: 1.61.0 version: 1.61.0 '@typescript-eslint/eslint-plugin': - specifier: ^8.58.1 - version: 8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2) + specifier: ^8.58.2 + version: 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2) '@typescript-eslint/parser': - specifier: ^8.58.1 - version: 8.58.1(eslint@10.2.0)(typescript@6.0.2) + specifier: ^8.58.2 + version: 8.58.2(eslint@10.2.0)(typescript@6.0.2) '@vscode/vsce': specifier: ^3.7.1 version: 3.7.1 @@ -59,28 +59,28 @@ importers: version: 10.1.8(eslint@10.2.0) eslint-plugin-import: specifier: ^2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0) + version: 2.32.0(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0) eslint-plugin-node: specifier: ^11.1.0 version: 11.1.0(eslint@10.2.0) eslint-plugin-prettier: specifier: ^5.5.5 - version: 5.5.5(eslint-config-prettier@10.1.8(eslint@10.2.0))(eslint@10.2.0)(prettier@3.8.1) + version: 5.5.5(eslint-config-prettier@10.1.8(eslint@10.2.0))(eslint@10.2.0)(prettier@3.8.2) npm-run-all2: specifier: ^8.0.4 version: 8.0.4 ovsx: - specifier: ^0.10.10 - version: 0.10.10 + specifier: ^0.10.11 + version: 0.10.11 prettier: - specifier: ^3.8.1 - version: 3.8.1 + specifier: ^3.8.2 + version: 3.8.2 typescript: specifier: ^6.0.2 version: 6.0.2 typescript-eslint: - specifier: ^8.58.1 - version: 8.58.1(eslint@10.2.0)(typescript@6.0.2) + specifier: ^8.58.2 + version: 8.58.2(eslint@10.2.0)(typescript@6.0.2) optionalDependencies: bufferutil: specifier: ^4.1.0 @@ -1116,63 +1116,63 @@ packages: '@types/vscode@1.61.0': resolution: {integrity: sha512-9k5Nwq45hkRwdfCFY+eKXeQQSbPoA114mF7U/4uJXRBJeGIO7MuJdhF1PnaDN+lllL9iKGQtd6FFXShBXMNaFg==} - '@typescript-eslint/eslint-plugin@8.58.1': - resolution: {integrity: sha512-eSkwoemjo76bdXl2MYqtxg51HNwUSkWfODUOQ3PaTLZGh9uIWWFZIjyjaJnex7wXDu+TRx+ATsnSxdN9YWfRTQ==} + '@typescript-eslint/eslint-plugin@8.58.2': + resolution: {integrity: sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.58.1 + '@typescript-eslint/parser': ^8.58.2 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.58.1': - resolution: {integrity: sha512-gGkiNMPqerb2cJSVcruigx9eHBlLG14fSdPdqMoOcBfh+vvn4iCq2C8MzUB89PrxOXk0y3GZ1yIWb9aOzL93bw==} + '@typescript-eslint/parser@8.58.2': + resolution: {integrity: sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.58.1': - resolution: {integrity: sha512-gfQ8fk6cxhtptek+/8ZIqw8YrRW5048Gug8Ts5IYcMLCw18iUgrZAEY/D7s4hkI0FxEfGakKuPK/XUMPzPxi5g==} + '@typescript-eslint/project-service@8.58.2': + resolution: {integrity: sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.58.1': - resolution: {integrity: sha512-TPYUEqJK6avLcEjumWsIuTpuYODTTDAtoMdt8ZZa93uWMTX13Nb8L5leSje1NluammvU+oI3QRr5lLXPgihX3w==} + '@typescript-eslint/scope-manager@8.58.2': + resolution: {integrity: sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.58.1': - resolution: {integrity: sha512-JAr2hOIct2Q+qk3G+8YFfqkqi7sC86uNryT+2i5HzMa2MPjw4qNFvtjnw1IiA1rP7QhNKVe21mSSLaSjwA1Olw==} + '@typescript-eslint/tsconfig-utils@8.58.2': + resolution: {integrity: sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.58.1': - resolution: {integrity: sha512-HUFxvTJVroT+0rXVJC7eD5zol6ID+Sn5npVPWoFuHGg9Ncq5Q4EYstqR+UOqaNRFXi5TYkpXXkLhoCHe3G0+7w==} + '@typescript-eslint/type-utils@8.58.2': + resolution: {integrity: sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.58.1': - resolution: {integrity: sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw==} + '@typescript-eslint/types@8.58.2': + resolution: {integrity: sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.58.1': - resolution: {integrity: sha512-w4w7WR7GHOjqqPnvAYbazq+Y5oS68b9CzasGtnd6jIeOIeKUzYzupGTB2T4LTPSv4d+WPeccbxuneTFHYgAAWg==} + '@typescript-eslint/typescript-estree@8.58.2': + resolution: {integrity: sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.58.1': - resolution: {integrity: sha512-Ln8R0tmWC7pTtLOzgJzYTXSCjJ9rDNHAqTaVONF4FEi2qwce8mD9iSOxOpLFFvWp/wBFlew0mjM1L1ihYWfBdQ==} + '@typescript-eslint/utils@8.58.2': + resolution: {integrity: sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.58.1': - resolution: {integrity: sha512-y+vH7QE8ycjoa0bWciFg7OpFcipUuem1ujhrdLtq1gByKwfbC7bPeKsiny9e0urg93DqwGcHey+bGRKCnF1nZQ==} + '@typescript-eslint/visitor-keys@8.58.2': + resolution: {integrity: sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typespec/ts-http-runtime@0.3.5': @@ -1343,8 +1343,8 @@ packages: boundary@2.0.0: resolution: {integrity: sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==} - brace-expansion@1.1.13: - resolution: {integrity: sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==} + brace-expansion@1.1.14: + resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} brace-expansion@5.0.5: resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} @@ -1375,8 +1375,8 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} engines: {node: '>= 0.4'} call-bound@1.0.4: @@ -1813,8 +1813,8 @@ packages: flatted@3.4.2: resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - follow-redirects@1.15.11: - resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -2228,8 +2228,8 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.3.3: - resolution: {integrity: sha512-JvNw9Y81y33E+BEYPr0U7omo+U9AySnsMsEiXgwT6yqd31VQWTLNQqmT4ou5eqPFUrTfIDFta2wKhB1hyohtAQ==} + lru-cache@11.3.5: + resolution: {integrity: sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==} engines: {node: 20 || >=22} lru-cache@6.0.0: @@ -2386,8 +2386,8 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} - ovsx@0.10.10: - resolution: {integrity: sha512-/X5J4VLKPUGGaMynW9hgvsGg9jmwsK/3RhODeA2yzdeDbb8PUSNcg5GQ9aPDJW/znlqNvAwQcXAyE+Cq0RRvAQ==} + ovsx@0.10.11: + resolution: {integrity: sha512-VYYlAWO7hvcrP0EIM/Q5lCdXTumXIiGyDnSXm8ztNbGN9zCSNW6iGiJMMMUNhPRWqJjNKpo/Vc2+B4uFRy8ACg==} engines: {node: '>= 20'} hasBin: true @@ -2489,8 +2489,8 @@ packages: resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==} engines: {node: '>=6.0.0'} - prettier@3.8.1: - resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + prettier@3.8.2: + resolution: {integrity: sha512-8c3mgTe0ASwWAJK+78dpviD+A8EqhndQPUBpNUIPt6+xWlIigCwfN01lWr9MAede4uqXGTEKeQWTvzb3vjia0Q==} engines: {node: '>=14'} hasBin: true @@ -2551,8 +2551,8 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - resolve@1.22.11: - resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} engines: {node: '>= 0.4'} hasBin: true @@ -2827,8 +2827,8 @@ packages: typed-rest-client@1.8.11: resolution: {integrity: sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==} - typescript-eslint@8.58.1: - resolution: {integrity: sha512-gf6/oHChByg9HJvhMO1iBexJh12AqqTfnuxscMDOVqfJW3htsdRJI/GfPpHTTcyeB8cSTUY2JcZmVgoyPqcrDg==} + typescript-eslint@8.58.2: + resolution: {integrity: sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -2852,8 +2852,8 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - undici@7.24.7: - resolution: {integrity: sha512-H/nlJ/h0ggGC+uRL3ovD+G0i4bqhvsDOpbDv7At5eFLlj2b41L8QliGbnl2H7SnDiYhENphh1tQFJZf+MyfLsQ==} + undici@7.25.0: + resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} engines: {node: '>=20.18.1'} unicorn-magic@0.1.0: @@ -3860,14 +3860,14 @@ snapshots: '@types/vscode@1.61.0': {} - '@typescript-eslint/eslint-plugin@8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2)': + '@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.58.1(eslint@10.2.0)(typescript@6.0.2) - '@typescript-eslint/scope-manager': 8.58.1 - '@typescript-eslint/type-utils': 8.58.1(eslint@10.2.0)(typescript@6.0.2) - '@typescript-eslint/utils': 8.58.1(eslint@10.2.0)(typescript@6.0.2) - '@typescript-eslint/visitor-keys': 8.58.1 + '@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/scope-manager': 8.58.2 + '@typescript-eslint/type-utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/visitor-keys': 8.58.2 eslint: 10.2.0 ignore: 7.0.5 natural-compare: 1.4.0 @@ -3876,41 +3876,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2)': + '@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2)': dependencies: - '@typescript-eslint/scope-manager': 8.58.1 - '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.2) - '@typescript-eslint/visitor-keys': 8.58.1 + '@typescript-eslint/scope-manager': 8.58.2 + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2) + '@typescript-eslint/visitor-keys': 8.58.2 debug: 4.4.3 eslint: 10.2.0 typescript: 6.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.58.1(typescript@6.0.2)': + '@typescript-eslint/project-service@8.58.2(typescript@6.0.2)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.58.1(typescript@6.0.2) - '@typescript-eslint/types': 8.58.1 + '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.2) + '@typescript-eslint/types': 8.58.2 debug: 4.4.3 typescript: 6.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.58.1': + '@typescript-eslint/scope-manager@8.58.2': dependencies: - '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/visitor-keys': 8.58.1 + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/visitor-keys': 8.58.2 - '@typescript-eslint/tsconfig-utils@8.58.1(typescript@6.0.2)': + '@typescript-eslint/tsconfig-utils@8.58.2(typescript@6.0.2)': dependencies: typescript: 6.0.2 - '@typescript-eslint/type-utils@8.58.1(eslint@10.2.0)(typescript@6.0.2)': + '@typescript-eslint/type-utils@8.58.2(eslint@10.2.0)(typescript@6.0.2)': dependencies: - '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.2) - '@typescript-eslint/utils': 8.58.1(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2) + '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2) debug: 4.4.3 eslint: 10.2.0 ts-api-utils: 2.5.0(typescript@6.0.2) @@ -3918,14 +3918,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.58.1': {} + '@typescript-eslint/types@8.58.2': {} - '@typescript-eslint/typescript-estree@8.58.1(typescript@6.0.2)': + '@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.2)': dependencies: - '@typescript-eslint/project-service': 8.58.1(typescript@6.0.2) - '@typescript-eslint/tsconfig-utils': 8.58.1(typescript@6.0.2) - '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/visitor-keys': 8.58.1 + '@typescript-eslint/project-service': 8.58.2(typescript@6.0.2) + '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.2) + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/visitor-keys': 8.58.2 debug: 4.4.3 minimatch: 10.2.5 semver: 7.7.4 @@ -3935,20 +3935,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.58.1(eslint@10.2.0)(typescript@6.0.2)': + '@typescript-eslint/utils@8.58.2(eslint@10.2.0)(typescript@6.0.2)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0) - '@typescript-eslint/scope-manager': 8.58.1 - '@typescript-eslint/types': 8.58.1 - '@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.2) + '@typescript-eslint/scope-manager': 8.58.2 + '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2) eslint: 10.2.0 typescript: 6.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.58.1': + '@typescript-eslint/visitor-keys@8.58.2': dependencies: - '@typescript-eslint/types': 8.58.1 + '@typescript-eslint/types': 8.58.2 eslint-visitor-keys: 5.0.1 '@typespec/ts-http-runtime@0.3.5': @@ -4079,7 +4079,7 @@ snapshots: array-includes@3.1.9: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 es-abstract: 1.24.2 @@ -4090,7 +4090,7 @@ snapshots: array.prototype.findlastindex@1.2.6: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 es-abstract: 1.24.2 @@ -4100,14 +4100,14 @@ snapshots: array.prototype.flat@1.3.3: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-abstract: 1.24.2 es-shim-unscopables: 1.1.0 array.prototype.flatmap@1.3.3: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-abstract: 1.24.2 es-shim-unscopables: 1.1.0 @@ -4115,7 +4115,7 @@ snapshots: arraybuffer.prototype.slice@1.0.4: dependencies: array-buffer-byte-length: 1.0.2 - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-abstract: 1.24.2 es-errors: 1.3.0 @@ -4161,7 +4161,7 @@ snapshots: boundary@2.0.0: {} - brace-expansion@1.1.13: + brace-expansion@1.1.14: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 @@ -4198,7 +4198,7 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 - call-bind@1.0.8: + call-bind@1.0.9: dependencies: call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 @@ -4239,7 +4239,7 @@ snapshots: parse5: 7.3.0 parse5-htmlparser2-tree-adapter: 7.1.0 parse5-parser-stream: 7.1.2 - undici: 7.24.7 + undici: 7.25.0 whatwg-mimetype: 4.0.0 chownr@1.1.4: @@ -4414,7 +4414,7 @@ snapshots: array-buffer-byte-length: 1.0.2 arraybuffer.prototype.slice: 1.0.4 available-typed-arrays: 1.0.7 - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 data-view-buffer: 1.0.2 data-view-byte-length: 1.0.2 @@ -4538,11 +4538,11 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2))(eslint-import-resolver-node@0.3.10)(eslint@10.2.0): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint-import-resolver-node@0.3.10)(eslint@10.2.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.58.1(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.2) eslint: 10.2.0 eslint-import-resolver-node: 0.3.10 transitivePeerDependencies: @@ -4554,7 +4554,7 @@ snapshots: eslint-utils: 2.1.0 regexpp: 3.2.0 - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -4565,7 +4565,7 @@ snapshots: doctrine: 2.1.0 eslint: 10.2.0 eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2))(eslint-import-resolver-node@0.3.10)(eslint@10.2.0) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint-import-resolver-node@0.3.10)(eslint@10.2.0) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -4577,7 +4577,7 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.58.1(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -4590,13 +4590,13 @@ snapshots: eslint-utils: 2.1.0 ignore: 5.3.2 minimatch: 3.1.5 - resolve: 1.22.11 + resolve: 1.22.12 semver: 6.3.1 - eslint-plugin-prettier@5.5.5(eslint-config-prettier@10.1.8(eslint@10.2.0))(eslint@10.2.0)(prettier@3.8.1): + eslint-plugin-prettier@5.5.5(eslint-config-prettier@10.1.8(eslint@10.2.0))(eslint@10.2.0)(prettier@3.8.2): dependencies: eslint: 10.2.0 - prettier: 3.8.1 + prettier: 3.8.2 prettier-linter-helpers: 1.0.1 synckit: 0.11.12 optionalDependencies: @@ -4737,7 +4737,7 @@ snapshots: flatted@3.4.2: {} - follow-redirects@1.15.11: {} + follow-redirects@1.16.0: {} for-each@0.3.5: dependencies: @@ -4769,7 +4769,7 @@ snapshots: function.prototype.name@1.1.8: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 functions-have-names: 1.2.3 @@ -4926,7 +4926,7 @@ snapshots: is-array-buffer@3.0.5: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 get-intrinsic: 1.3.0 @@ -5169,7 +5169,7 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.3.3: {} + lru-cache@11.3.5: {} lru-cache@6.0.0: dependencies: @@ -5214,7 +5214,7 @@ snapshots: minimatch@3.1.5: dependencies: - brace-expansion: 1.1.13 + brace-expansion: 1.1.14 minimist@1.2.8: {} @@ -5286,7 +5286,7 @@ snapshots: object.assign@4.1.7: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 @@ -5295,27 +5295,27 @@ snapshots: object.entries@1.1.9: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 object.fromentries@2.0.8: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-abstract: 1.24.2 es-object-atoms: 1.1.1 object.groupby@1.0.3: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-abstract: 1.24.2 object.values@1.2.1: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 @@ -5343,11 +5343,11 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 - ovsx@0.10.10: + ovsx@0.10.11: dependencies: '@vscode/vsce': 3.7.1 commander: 6.2.1 - follow-redirects: 1.15.11 + follow-redirects: 1.16.0 is-ci: 2.0.0 leven: 3.1.0 semver: 7.7.4 @@ -5406,7 +5406,7 @@ snapshots: path-scurry@2.0.2: dependencies: - lru-cache: 11.3.3 + lru-cache: 11.3.5 minipass: 7.1.3 path-type@6.0.0: {} @@ -5449,7 +5449,7 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier@3.8.1: {} + prettier@3.8.2: {} pump@3.0.4: dependencies: @@ -5510,7 +5510,7 @@ snapshots: reflect.getprototypeof@1.0.10: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-abstract: 1.24.2 es-errors: 1.3.0 @@ -5521,7 +5521,7 @@ snapshots: regexp.prototype.flags@1.5.4: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-errors: 1.3.0 get-proto: 1.0.1 @@ -5532,8 +5532,9 @@ snapshots: require-from-string@2.0.2: {} - resolve@1.22.11: + resolve@1.22.12: dependencies: + es-errors: 1.3.0 is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -5557,7 +5558,7 @@ snapshots: safe-array-concat@1.1.3: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 get-intrinsic: 1.3.0 has-symbols: 1.1.0 @@ -5705,7 +5706,7 @@ snapshots: string.prototype.trim@1.2.10: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-data-property: 1.1.4 define-properties: 1.2.1 @@ -5715,14 +5716,14 @@ snapshots: string.prototype.trimend@1.0.9: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 string.prototype.trimstart@1.0.8: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-object-atoms: 1.1.1 @@ -5846,7 +5847,7 @@ snapshots: typed-array-byte-length@1.0.3: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 for-each: 0.3.5 gopd: 1.2.0 has-proto: 1.2.0 @@ -5855,7 +5856,7 @@ snapshots: typed-array-byte-offset@1.0.4: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.8 + call-bind: 1.0.9 for-each: 0.3.5 gopd: 1.2.0 has-proto: 1.2.0 @@ -5864,7 +5865,7 @@ snapshots: typed-array-length@1.0.7: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 for-each: 0.3.5 gopd: 1.2.0 is-typed-array: 1.1.15 @@ -5877,12 +5878,12 @@ snapshots: tunnel: 0.0.6 underscore: 1.13.8 - typescript-eslint@8.58.1(eslint@10.2.0)(typescript@6.0.2): + typescript-eslint@8.58.2(eslint@10.2.0)(typescript@6.0.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.58.1(@typescript-eslint/parser@8.58.1(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2) - '@typescript-eslint/parser': 8.58.1(eslint@10.2.0)(typescript@6.0.2) - '@typescript-eslint/typescript-estree': 8.58.1(typescript@6.0.2) - '@typescript-eslint/utils': 8.58.1(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.0)(typescript@6.0.2))(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/parser': 8.58.2(eslint@10.2.0)(typescript@6.0.2) + '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.2) + '@typescript-eslint/utils': 8.58.2(eslint@10.2.0)(typescript@6.0.2) eslint: 10.2.0 typescript: 6.0.2 transitivePeerDependencies: @@ -5903,7 +5904,7 @@ snapshots: undici-types@7.16.0: {} - undici@7.24.7: {} + undici@7.25.0: {} unicorn-magic@0.1.0: {} @@ -5971,7 +5972,7 @@ snapshots: which-typed-array@1.1.20: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 for-each: 0.3.5 get-proto: 1.0.1 diff --git a/server/Cargo.lock b/server/Cargo.lock index 30a5f5f..66b558f 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -8,7 +8,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "bytes", "futures-core", "futures-sink", @@ -29,7 +29,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web", - "bitflags 2.11.0", + "bitflags 2.11.1", "bytes", "derive_more", "futures-core", @@ -53,7 +53,7 @@ dependencies = [ "actix-service", "actix-utils", "base64", - "bitflags 2.11.0", + "bitflags 2.11.1", "brotli", "bytes", "bytestring", @@ -72,7 +72,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rand 0.9.2", + "rand 0.9.4", "sha1", "smallvec", "tokio", @@ -546,9 +546,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] name = "block-buffer" @@ -664,9 +664,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.59" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" dependencies = [ "find-msvc-tools", "jobserver", @@ -711,7 +711,7 @@ checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" dependencies = [ "cfg-if", "cpufeatures 0.3.0", - "rand_core 0.10.0", + "rand_core 0.10.1", ] [[package]] @@ -785,7 +785,7 @@ checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" [[package]] name = "codechat-editor-server" -version = "0.1.52" +version = "0.1.53" dependencies = [ "actix-files", "actix-http", @@ -808,6 +808,7 @@ dependencies = [ "futures-util", "htmd", "html5ever", + "htmlize", "imara-diff", "indoc", "lazy_static", @@ -826,7 +827,7 @@ dependencies = [ "predicates", "pretty_assertions", "pulldown-cmark 0.13.3", - "rand 0.10.0", + "rand 0.10.1", "regex", "serde", "serde_json", @@ -1215,7 +1216,7 @@ dependencies = [ "anyhow", "bumpalo", "hashbrown 0.15.5", - "indexmap 2.13.1", + "indexmap 2.14.0", "rustc-hash", "serde", "unicode-width", @@ -1554,7 +1555,7 @@ dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", - "rand_core 0.10.0", + "rand_core 0.10.1", "wasip2", "wasip3", ] @@ -1578,7 +1579,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "ignore", "walkdir", ] @@ -1595,7 +1596,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.13.1", + "indexmap 2.14.0", "slab", "tokio", "tokio-util", @@ -1621,9 +1622,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" [[package]] name = "heck" @@ -1666,6 +1667,16 @@ dependencies = [ "markup5ever", ] +[[package]] +name = "htmlize" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e815d50d9e411ba2690d730e6ec139c08260dddb756df315dbd16d01a587226" +dependencies = [ + "memchr", + "pastey 0.1.1", +] + [[package]] name = "http" version = "0.2.12" @@ -1765,15 +1776,14 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.7" +version = "0.27.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +checksum = "c2b52f86d1d4bc0d6b4e6826d960b1b333217e07d36b882dca570a5e1c48895b" dependencies = [ "http 1.4.0", "hyper", "hyper-util", "rustls", - "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", @@ -1980,12 +1990,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.1" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "serde", "serde_core", ] @@ -2023,7 +2033,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "inotify-sys", "libc", ] @@ -2184,9 +2194,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.94" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" +checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" dependencies = [ "cfg-if", "futures-util", @@ -2240,20 +2250,20 @@ checksum = "2c4a545a15244c7d945065b5d392b2d2d7f21526fba56ce51467b06ed445e8f7" [[package]] name = "libc" -version = "0.2.184" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "libredox" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "libc", "plain", - "redox_syscall 0.7.3", + "redox_syscall 0.7.4", ] [[package]] @@ -2326,7 +2336,7 @@ dependencies = [ "log-mdc", "mock_instant", "parking_lot", - "rand 0.9.2", + "rand 0.9.4", "serde", "serde-value", "serde_json", @@ -2487,7 +2497,7 @@ version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "fsevent-sys", "inotify", "kqueue", @@ -2518,7 +2528,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] @@ -2561,7 +2571,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] @@ -2576,7 +2586,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "objc2", ] @@ -2645,6 +2655,12 @@ dependencies = [ "windows-link", ] +[[package]] +name = "pastey" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" + [[package]] name = "pastey" version = "0.2.1" @@ -2777,9 +2793,9 @@ checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "plain" @@ -2815,7 +2831,7 @@ dependencies = [ "hmac", "md-5 0.11.0", "memchr", - "rand 0.10.0", + "rand 0.10.1", "sha2 0.11.0", "stringprep", ] @@ -2927,7 +2943,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "memchr", "unicase", ] @@ -2938,7 +2954,7 @@ version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c3a14896dfa883796f1cb410461aef38810ea05f2b2c33c5aded3649095fdad" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "memchr", "pulldown-cmark-escape", "unicase", @@ -2980,7 +2996,7 @@ dependencies = [ "bytes", "getrandom 0.3.4", "lru-slab", - "rand 0.9.2", + "rand 0.9.4", "ring", "rustc-hash", "rustls", @@ -3040,9 +3056,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.5", @@ -3050,13 +3066,13 @@ dependencies = [ [[package]] name = "rand" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ "chacha20", "getrandom 0.4.2", - "rand_core 0.10.0", + "rand_core 0.10.1", ] [[package]] @@ -3099,9 +3115,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "redox_syscall" @@ -3109,16 +3125,16 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] name = "redox_syscall" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" +checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] @@ -3279,7 +3295,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "errno", "libc", "linux-raw-sys", @@ -3288,9 +3304,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "69f9466fb2c14ea04357e91413efb882e2a6d4a406e625449bc0a5d360d53a21" dependencies = [ "aws-lc-rs", "once_cell", @@ -3352,9 +3368,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.10" +version = "0.103.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +checksum = "8279bb85272c9f10811ae6a6c547ff594d6a7f3c6c6b02ee9726d1d0dcfcdd06" dependencies = [ "aws-lc-rs", "ring", @@ -3424,7 +3440,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "core-foundation", "core-foundation-sys", "libc", @@ -3539,7 +3555,7 @@ version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ - "indexmap 2.13.1", + "indexmap 2.14.0", "itoa", "memchr", "serde", @@ -3585,7 +3601,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.13.1", + "indexmap 2.14.0", "itoa", "ryu", "serde", @@ -3919,9 +3935,9 @@ dependencies = [ "const_format", "futures-util", "http 1.4.0", - "indexmap 2.13.1", + "indexmap 2.14.0", "libc", - "pastey", + "pastey 0.2.1", "reqwest 0.13.2", "selenium-manager", "serde", @@ -4098,7 +4114,7 @@ dependencies = [ "pin-project-lite", "postgres-protocol", "postgres-types", - "rand 0.10.0", + "rand 0.10.1", "socket2 0.6.3", "tokio", "tokio-util", @@ -4147,7 +4163,7 @@ version = "0.9.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" dependencies = [ - "indexmap 2.13.1", + "indexmap 2.14.0", "serde_core", "serde_spanned", "toml_datetime", @@ -4201,7 +4217,7 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "bytes", "futures-util", "http 1.4.0", @@ -4296,7 +4312,7 @@ dependencies = [ "http 1.4.0", "httparse", "log", - "rand 0.9.2", + "rand 0.9.4", "sha1", "thiserror 2.0.18", ] @@ -4524,9 +4540,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.117" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" +checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" dependencies = [ "cfg-if", "once_cell", @@ -4537,9 +4553,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.67" +version = "0.4.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03623de6905b7206edd0a75f69f747f134b7f0a2323392d664448bf2d3c5d87e" +checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8" dependencies = [ "js-sys", "wasm-bindgen", @@ -4547,9 +4563,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.117" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" +checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4557,9 +4573,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.117" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" +checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" dependencies = [ "bumpalo", "proc-macro2", @@ -4570,9 +4586,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.117" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" +checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" dependencies = [ "unicode-ident", ] @@ -4594,7 +4610,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ "anyhow", - "indexmap 2.13.1", + "indexmap 2.14.0", "wasm-encoder", "wasmparser", ] @@ -4605,17 +4621,17 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "hashbrown 0.15.5", - "indexmap 2.13.1", + "indexmap 2.14.0", "semver", ] [[package]] name = "web-sys" -version = "0.3.94" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" +checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d" dependencies = [ "js-sys", "wasm-bindgen", @@ -5102,7 +5118,7 @@ checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", "heck", - "indexmap 2.13.1", + "indexmap 2.14.0", "prettyplease", "syn 2.0.117", "wasm-metadata", @@ -5132,8 +5148,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.0", - "indexmap 2.13.1", + "bitflags 2.11.1", + "indexmap 2.14.0", "log", "serde", "serde_derive", @@ -5152,7 +5168,7 @@ checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ "anyhow", "id-arena", - "indexmap 2.13.1", + "indexmap 2.14.0", "log", "semver", "serde", @@ -5354,7 +5370,7 @@ dependencies = [ "arbitrary", "crc32fast", "flate2", - "indexmap 2.13.1", + "indexmap 2.14.0", "memchr", "zopfli", ] diff --git a/server/Cargo.toml b/server/Cargo.toml index 741b7fa..d8e5070 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -32,7 +32,7 @@ license = "GPL-3.0-only" name = "codechat-editor-server" readme = "../README.md" repository = "https://github.com/bjones1/CodeChat_Editor" -version = "0.1.52" +version = "0.1.53" # This library allows other packages to use core CodeChat Editor features. [lib] From cfefa47e5e71d4ca3f57f99cc75f252499b92ddf Mon Sep 17 00:00:00 2001 From: "Bryan A. Jones" Date: Tue, 14 Apr 2026 18:32:03 +0500 Subject: [PATCH 9/9] Update changelog for release. --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4a2d34..808d9c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,11 @@ Changelog [Github master](https://github.com/bjones1/CodeChat_Editor) ----------------------------------------------------------- +*  No changes. + +Version 0.1.53 -- 2026-Apr-14 +----------------------------- + * Claude code reviews revealed the following issues, which were fixed manually: * Fix multi-byte Unicode encoding bug. * Fix incorrect websocket shutdown sequence.