From 1d59e4bbd78ca2c2378edb0525e212acb2bc38e9 Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Thu, 3 Jul 2025 02:25:00 +0200 Subject: [PATCH] refactor: bump rust to 1.88, use the new niceties (#161) --- .github/workflows/ci.yml | 10 +-- src/cli/check.rs | 52 ++++++++-------- src/cli/format.rs | 47 +++++++------- src/cli/lint.rs | 7 +-- src/cli/profile.rs | 90 +++++++++++++-------------- src/handlers/completion.rs | 107 ++++++++++++++++---------------- src/handlers/did_open.rs | 48 +++++++------- src/handlers/document_symbol.rs | 4 +- src/handlers/formatting.rs | 11 ++-- src/util.rs | 30 ++++----- 10 files changed, 198 insertions(+), 208 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 32df88e..d52a559 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.86.0 + - uses: dtolnay/rust-toolchain@1.88.0 id: toolchain with: components: clippy @@ -35,7 +35,7 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.86.0 + - uses: dtolnay/rust-toolchain@1.88.0 id: toolchain with: components: rustfmt @@ -47,7 +47,7 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.86.0 + - uses: dtolnay/rust-toolchain@1.88.0 id: toolchain - uses: actions/cache@v3 with: @@ -68,7 +68,7 @@ jobs: steps: - uses: actions/checkout@v4 - uses: tree-sitter/setup-action/cli@v1 - - uses: dtolnay/rust-toolchain@1.86.0 + - uses: dtolnay/rust-toolchain@1.88.0 id: toolchain - uses: actions/cache@v3 with: @@ -121,7 +121,7 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.86.0 + - uses: dtolnay/rust-toolchain@1.88.0 id: toolchain - uses: actions/cache@v3 with: diff --git a/src/cli/check.rs b/src/cli/check.rs index 621de21..25033a8 100644 --- a/src/cli/check.rs +++ b/src/cli/check.rs @@ -50,38 +50,36 @@ pub async fn check_directories( .map(|lang| Arc::new(init_language_data(lang, name))) }) }); - if let Some(lang) = language_data { - if let Ok(source) = fs::read_to_string(&path) { - return Some(tokio::spawn(async move { - if let Some(new_source) = lint_file( - &path, - &uri, - &source, - options_arc.clone(), - fix, - Some(lang), - &exit_code, - ) - .await - { - if fs::write(&path, new_source).is_err() { - eprintln!("Failed to write {:?}", path.canonicalize().unwrap()); - exit_code.store(1, std::sync::atomic::Ordering::Relaxed); - } - }; - })); - } else { - eprintln!("Failed to read {:?}", path.canonicalize().unwrap()); - exit_code.store(1, std::sync::atomic::Ordering::Relaxed); - } - } else { + let Some(lang) = language_data else { exit_code.store(1, std::sync::atomic::Ordering::Relaxed); eprintln!( "Could not retrieve language for {:?}", path.canonicalize().unwrap() - ) + ); + return None; }; - None + let Ok(source) = fs::read_to_string(&path) else { + eprintln!("Failed to read {:?}", path.canonicalize().unwrap()); + exit_code.store(1, std::sync::atomic::Ordering::Relaxed); + return None; + }; + Some(tokio::spawn(async move { + if let Some(new_source) = lint_file( + &path, + &uri, + &source, + options_arc.clone(), + fix, + Some(lang), + &exit_code, + ) + .await + && fs::write(&path, new_source).is_err() + { + eprintln!("Failed to write {:?}", path.canonicalize().unwrap()); + exit_code.store(1, std::sync::atomic::Ordering::Relaxed); + }; + })) }); join_all(tasks).await; if format && format_directories(directories, true).await != 0 { diff --git a/src/cli/format.rs b/src/cli/format.rs index b2c711b..f686869 100644 --- a/src/cli/format.rs +++ b/src/cli/format.rs @@ -21,31 +21,32 @@ pub async fn format_directories(directories: &[PathBuf], check: bool) -> i32 { let tasks = scm_files.into_iter().map(|path| { let exit_code = exit_code.clone(); tokio::spawn(async move { - if let Ok(contents) = fs::read_to_string(&path) { - let mut parser = tree_sitter::Parser::new(); - parser - .set_language(&QUERY_LANGUAGE) - .expect("Error loading Query grammar"); - let tree = parser.parse(contents.as_str(), None).unwrap(); - let rope = Rope::from(contents.as_str()); - if let Some(formatted) = formatting::format_document(&rope, &tree.root_node()) { - if check { - let edits = formatting::diff(&contents, &formatted, &rope); - if !edits.is_empty() { - exit_code.store(1, std::sync::atomic::Ordering::Relaxed); - eprintln!( - "Improper formatting detected for {:?}", - path.canonicalize().unwrap() - ); - } - } else if fs::write(&path, formatted).is_err() { - exit_code.store(1, std::sync::atomic::Ordering::Relaxed); - eprint!("Failed to write to {:?}", path.canonicalize().unwrap()) - } - } - } else { + let Ok(contents) = fs::read_to_string(&path) else { eprintln!("Failed to read {:?}", path.canonicalize().unwrap()); exit_code.store(1, std::sync::atomic::Ordering::Relaxed); + return; + }; + let mut parser = tree_sitter::Parser::new(); + parser + .set_language(&QUERY_LANGUAGE) + .expect("Error loading Query grammar"); + let tree = parser.parse(contents.as_str(), None).unwrap(); + let rope = Rope::from(contents.as_str()); + let Some(formatted) = formatting::format_document(&rope, &tree.root_node()) else { + return; + }; + if check { + let edits = formatting::diff(&contents, &formatted, &rope); + if !edits.is_empty() { + exit_code.store(1, std::sync::atomic::Ordering::Relaxed); + eprintln!( + "Improper formatting detected for {:?}", + path.canonicalize().unwrap() + ); + } + } else if fs::write(&path, formatted).is_err() { + exit_code.store(1, std::sync::atomic::Ordering::Relaxed); + eprint!("Failed to write to {:?}", path.canonicalize().unwrap()) } }) }); diff --git a/src/cli/lint.rs b/src/cli/lint.rs index 1eb0a89..d4436ac 100644 --- a/src/cli/lint.rs +++ b/src/cli/lint.rs @@ -128,11 +128,10 @@ pub async fn lint_directories(directories: &[PathBuf], config: String, fix: bool Some(tokio::spawn(async move { if let Some(new_source) = lint_file(&path, &uri, &source, options, fix, None, &exit_code).await + && fs::write(&path, new_source).is_err() { - if fs::write(&path, new_source).is_err() { - eprintln!("Failed to write {:?}", path.canonicalize().unwrap()); - exit_code.store(1, std::sync::atomic::Ordering::Relaxed); - } + eprintln!("Failed to write {:?}", path.canonicalize().unwrap()); + exit_code.store(1, std::sync::atomic::Ordering::Relaxed); }; })) } else { diff --git a/src/cli/profile.rs b/src/cli/profile.rs index bf109d0..711815f 100644 --- a/src/cli/profile.rs +++ b/src/cli/profile.rs @@ -43,57 +43,53 @@ pub async fn profile_directories(directories: &[PathBuf], config: String, per_fi .map(|lang| Arc::new(init_language_data(lang, name))) }) }); - if let Some(lang_data) = language_data { - let lang = lang_data.language.clone().unwrap(); - if let Ok(source) = fs::read_to_string(&path) { - Some(tokio::spawn(async move { - let mut results = Vec::new(); - if per_file { - let now = Instant::now(); - let _ = Query::new(&lang, &source); - results.push((path_str.clone(), 1, now.elapsed().as_micros())); - } else { - let mut parser = Parser::new(); - parser.set_language(&QUERY_LANGUAGE).unwrap(); - let tree = parser.parse(&source, None).expect("Tree should exist"); - let mut cursor = QueryCursor::new(); - let source_bytes = source.as_bytes(); - let mut matches = cursor.matches( - &PATTERN_DEFINITION_QUERY, - tree.root_node(), - source_bytes, - ); - while let Some(match_) = matches.next() { - for capture in match_.captures { - let now = Instant::now(); - let _ = Query::new( - &lang, - capture - .node - .utf8_text(source_bytes) - .expect("Source should be UTF-8"), - ); - results.push(( - path_str.clone(), - capture.node.start_position().row + 1, - now.elapsed().as_micros(), - )); - } - } - } - results - })) - } else { - eprintln!("Failed to read {:?}", path.canonicalize().unwrap()); - None - } - } else { + let Some(lang_data) = language_data else { eprintln!( "Could not retrieve language for {:?}", path.canonicalize().unwrap() ); - None - } + return None; + }; + let lang = lang_data.language.clone().unwrap(); + let Ok(source) = fs::read_to_string(&path) else { + eprintln!("Failed to read {:?}", path.canonicalize().unwrap()); + return None; + }; + Some(tokio::spawn(async move { + if per_file { + let now = Instant::now(); + let _ = Query::new(&lang, &source); + return vec![(path_str.clone(), 1, now.elapsed().as_micros())]; + } + + let mut results = Vec::new(); + let mut parser = Parser::new(); + parser.set_language(&QUERY_LANGUAGE).unwrap(); + let tree = parser.parse(&source, None).expect("Tree should exist"); + let mut cursor = QueryCursor::new(); + let source_bytes = source.as_bytes(); + let mut matches = + cursor.matches(&PATTERN_DEFINITION_QUERY, tree.root_node(), source_bytes); + + while let Some(match_) = matches.next() { + for capture in match_.captures { + let now = Instant::now(); + let _ = Query::new( + &lang, + capture + .node + .utf8_text(source_bytes) + .expect("Source should be UTF-8"), + ); + results.push(( + path_str.clone(), + capture.node.start_position().row + 1, + now.elapsed().as_micros(), + )); + } + } + results + })) }); let results = join_all(tasks).await; let mut results = results diff --git a/src/handlers/completion.rs b/src/handlers/completion.rs index 7afbacd..55327e3 100644 --- a/src/handlers/completion.rs +++ b/src/handlers/completion.rs @@ -159,64 +159,65 @@ pub async fn completion( let in_capture = cursor_after_at_sign || node_is_or_has_ancestor(root, current_node, "capture"); let in_predicate = node_is_or_has_ancestor(root, current_node, "predicate"); let in_missing = node_is_or_has_ancestor(root, current_node, "missing_node"); - if !in_capture && !in_predicate { - if let Some(language_data) = language_data { - let symbols = &language_data.symbols_vec; - let supertypes = &language_data.supertype_map; - let fields = &language_data.fields_vec; - let in_anon = node_is_or_has_ancestor(root, current_node, "string") && !in_predicate; - let top_level = current_node.kind() == "program"; - let in_negated_field = current_node.kind() == "negated_field" - || cursor_after_exclamation_point - || (current_node.kind() == "identifier" - && current_node - .parent() - .is_some_and(|p| p.kind() == "negated_field")); + if !in_capture + && !in_predicate + && let Some(language_data) = language_data + { + let symbols = &language_data.symbols_vec; + let supertypes = &language_data.supertype_map; + let fields = &language_data.fields_vec; + let in_anon = node_is_or_has_ancestor(root, current_node, "string") && !in_predicate; + let top_level = current_node.kind() == "program"; + let in_negated_field = current_node.kind() == "negated_field" + || cursor_after_exclamation_point + || (current_node.kind() == "identifier" + && current_node + .parent() + .is_some_and(|p| p.kind() == "negated_field")); - if in_negated_field { - for field in fields.clone() { - completion_items.push(CompletionItem { - label: field, - kind: Some(CompletionItemKind::FIELD), - ..Default::default() - }); - } - return Ok(Some(CompletionResponse::Array(completion_items))); + if in_negated_field { + for field in fields.clone() { + completion_items.push(CompletionItem { + label: field, + kind: Some(CompletionItemKind::FIELD), + ..Default::default() + }); } - if !top_level { - for symbol in symbols.iter() { - if (in_anon && !symbol.named) || (!in_anon && symbol.named) { - completion_items.push(CompletionItem { - label: symbol.label.clone(), - kind: if symbol.named { - if !supertypes.contains_key(symbol) { - Some(CompletionItemKind::CLASS) - } else { - Some(CompletionItemKind::INTERFACE) - } + return Ok(Some(CompletionResponse::Array(completion_items))); + } + if !top_level { + for symbol in symbols.iter() { + if (in_anon && !symbol.named) || (!in_anon && symbol.named) { + completion_items.push(CompletionItem { + label: symbol.label.clone(), + kind: if symbol.named { + if !supertypes.contains_key(symbol) { + Some(CompletionItemKind::CLASS) } else { - Some(CompletionItemKind::CONSTANT) - }, - ..Default::default() - }); - } + Some(CompletionItemKind::INTERFACE) + } + } else { + Some(CompletionItemKind::CONSTANT) + }, + ..Default::default() + }); } } - if !in_missing && !in_anon { - if !top_level { - completion_items.push(CompletionItem { - label: String::from("MISSING"), - kind: Some(CompletionItemKind::KEYWORD), - ..Default::default() - }); - } - for field in fields { - completion_items.push(CompletionItem { - label: format!("{field}: "), - kind: Some(CompletionItemKind::FIELD), - ..Default::default() - }); - } + } + if !in_missing && !in_anon { + if !top_level { + completion_items.push(CompletionItem { + label: String::from("MISSING"), + kind: Some(CompletionItemKind::KEYWORD), + ..Default::default() + }); + } + for field in fields { + completion_items.push(CompletionItem { + label: format!("{field}: "), + kind: Some(CompletionItemKind::FIELD), + ..Default::default() + }); } } } diff --git a/src/handlers/did_open.rs b/src/handlers/did_open.rs index 0979da0..471b230 100644 --- a/src/handlers/did_open.rs +++ b/src/handlers/did_open.rs @@ -130,30 +130,30 @@ pub async fn populate_import_documents( imported_uris: &Vec<(u32, u32, Option)>, ) { for (_, _, uri) in imported_uris { - if let Some(uri) = uri { - if !backend.document_map.contains_key(uri) { - let path = uri.to_file_path().unwrap(); - if let Ok(contents) = fs::read_to_string(path) { - let rope = Rope::from_str(&contents); - let mut parser = Parser::new(); - parser - .set_language(&QUERY_LANGUAGE) - .expect("Error loading Query grammar"); - let tree = parser.parse(&contents, None).unwrap(); - let nested_imported_uris = get_imported_uris(backend, uri, &rope, &tree).await; - backend.document_map.insert( - uri.clone(), - DocumentData { - rope, - tree, - language_name: None, - version: -1, - imported_uris: nested_imported_uris.clone(), - }, - ); - Box::pin(populate_import_documents(backend, &nested_imported_uris)).await - } - } + if let Some(uri) = uri + && !backend.document_map.contains_key(uri) + && let Ok(contents) = uri + .to_file_path() + .and_then(|path| fs::read_to_string(path).map_err(|_| ())) + { + let rope = Rope::from_str(&contents); + let mut parser = Parser::new(); + parser + .set_language(&QUERY_LANGUAGE) + .expect("Error loading Query grammar"); + let tree = parser.parse(&contents, None).unwrap(); + let nested_imported_uris = get_imported_uris(backend, uri, &rope, &tree).await; + backend.document_map.insert( + uri.clone(), + DocumentData { + rope, + tree, + language_name: None, + version: -1, + imported_uris: nested_imported_uris.clone(), + }, + ); + Box::pin(populate_import_documents(backend, &nested_imported_uris)).await } } } diff --git a/src/handlers/document_symbol.rs b/src/handlers/document_symbol.rs index f8764b2..5ea3ad2 100644 --- a/src/handlers/document_symbol.rs +++ b/src/handlers/document_symbol.rs @@ -33,7 +33,6 @@ pub async fn document_symbol( let capture_node = capture.node; let node_text = capture_node.text(rope); let parent = capture_node.parent().unwrap(); - #[allow(deprecated)] document_symbols.push(DocumentSymbol { name: node_text, kind: SymbolKind::VARIABLE, @@ -43,6 +42,7 @@ pub async fn document_symbol( // TODO: Structure this hierarchically children: None, tags: None, + #[allow(deprecated)] deprecated: None, }); } @@ -172,7 +172,6 @@ mod test { // Assert let actual = Some(DocumentSymbolResponse::Nested( - #[allow(deprecated)] symbols .iter() .map(|s| DocumentSymbol { @@ -183,6 +182,7 @@ mod test { detail: None, children: None, tags: None, + #[allow(deprecated)] deprecated: None, }) .collect(), diff --git a/src/handlers/formatting.rs b/src/handlers/formatting.rs index 3c34834..2eb5ad6 100644 --- a/src/handlers/formatting.rs +++ b/src/handlers/formatting.rs @@ -230,8 +230,7 @@ fn format_iter<'a>( } } if map.comment_fix.contains(id) { - let text = child.text(rope); - if let Some(mat) = COMMENT_PAT.captures(text.as_str()) { + if let Some(mat) = COMMENT_PAT.captures(&child.text(rope)) { lines .last_mut() .unwrap() @@ -310,10 +309,10 @@ fn handle_predicate( Some(node) => node.kind(), }; for arg in &args[1..] { - if let QueryPredicateArg::String(kind) = arg { - if node_type == kind.deref() { - return false; - } + if let QueryPredicateArg::String(kind) = arg + && node_type == kind.deref() + { + return false; } } } diff --git a/src/util.rs b/src/util.rs index 99b2a0b..8fdc940 100644 --- a/src/util.rs +++ b/src/util.rs @@ -285,13 +285,12 @@ fn get_first_valid_file_config(workspace_uris: Vec) -> Option { if let Ok(mut path) = folder_url.to_file_path() { let mut config_path = path.join(".tsqueryrc.json"); loop { - if config_path.is_file() { - let data = fs::read_to_string(&config_path) + if config_path.is_file() + && let Some(options) = fs::read_to_string(&config_path) .ok() - .and_then(|data| serde_json::from_str(&data).ok()); - if let Some(options) = data { - return options; - } + .and_then(|data| serde_json::from_str(&data).ok()) + { + return options; } path = match path.parent() { Some(parent) => parent.into(), @@ -386,23 +385,20 @@ pub async fn get_file_uris(backend: &Backend, language_name: &str, query_type: & .iter() .filter_map(|uri| uri.to_file_path().ok()) .collect::>(); - let scm_files = get_scm_files(&dirs); let language_retrieval_regexes = &backend.options.read().await.language_retrieval_patterns; let mut urls = Vec::new(); - for scm_file in scm_files { + for scm_file in get_scm_files(&dirs) { for re in language_retrieval_regexes { - if let Some(lang_name) = re - .captures(&scm_file.canonicalize().unwrap().to_string_lossy()) - .and_then(|caps| caps.get(1)) + if scm_file.file_stem().is_some_and(|stem| stem == query_type) + && let Some(lang_name) = re + .captures(&scm_file.canonicalize().unwrap().to_string_lossy()) + .and_then(|caps| caps.get(1)) + && lang_name.as_str() == language_name { - if lang_name.as_str() == language_name - && scm_file.file_stem().is_some_and(|stem| stem == query_type) - { - urls.push(Url::from_file_path(&scm_file).unwrap()); - break; - } + urls.push(Url::from_file_path(&scm_file).unwrap()); + break; } } }