diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 00f80bafb..f17f62cbb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,31 +24,23 @@ jobs: name: Rustfmt runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable with: toolchain: nightly components: rustfmt - override: true - - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check + - name: Run fmt + run: cargo +nightly fmt --all -- --check clippy: name: Clippy runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - components: clippy - override: true - - uses: actions-rs/clippy-check@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - args: --all-features --all-targets --manifest-path Cargo.toml -- -D warnings + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - name: Run clippy + run: | + cargo clippy --locked --all-features --all-targets --manifest-path Cargo.toml -- -D warnings crates: name: Rust Tests diff --git a/crates/cli/src/command/ctags/recursive_tags.rs b/crates/cli/src/command/ctags/recursive_tags.rs index 91905a836..108092285 100644 --- a/crates/cli/src/command/ctags/recursive_tags.rs +++ b/crates/cli/src/command/ctags/recursive_tags.rs @@ -6,10 +6,9 @@ use clap::Parser; use filter::{FilterContext, SequentialSource}; use itertools::Itertools; use maple_core::process::ShellCommand; -use maple_core::tools::ctags::{ProjectCtagsCommand, CTAGS_HAS_JSON_FEATURE}; +use maple_core::tools::ctags::{ProjectCtagsCommand, CTAGS_BIN}; use matcher::{MatchScope, MatcherBuilder}; use rayon::prelude::*; -use std::ops::Deref; use std::sync::Arc; use types::ClapItem; @@ -65,11 +64,7 @@ impl RecursiveTags { .. }: Args, ) -> Result<()> { - if !CTAGS_HAS_JSON_FEATURE.deref() { - return Err(anyhow::anyhow!( - "ctags executable is not compiled with +json feature, please recompile it." - )); - } + CTAGS_BIN.ensure_json_feature()?; let mut ctags_cmd = self.project_ctags_cmd()?; diff --git a/crates/code_tools/src/linting/linters/typos.rs b/crates/code_tools/src/linting/linters/typos.rs index f5140eded..48151d32b 100644 --- a/crates/code_tools/src/linting/linters/typos.rs +++ b/crates/code_tools/src/linting/linters/typos.rs @@ -76,7 +76,7 @@ enum Message<'m> { Typo(Typo<'m>), } -impl<'m> Message<'m> { +impl Message<'_> { fn try_into_diagnostic(self) -> Option { match self { Self::Typo(typo) => { diff --git a/crates/code_tools/src/linting/mod.rs b/crates/code_tools/src/linting/mod.rs index 6d438a036..488618e82 100644 --- a/crates/code_tools/src/linting/mod.rs +++ b/crates/code_tools/src/linting/mod.rs @@ -119,7 +119,7 @@ enum WorkspaceMarker { } impl WorkspaceMarker { - fn find_workspace<'a>(&'a self, source_file: &'a Path) -> Option<&Path> { + fn find_workspace<'a>(&self, source_file: &'a Path) -> Option<&'a Path> { match self { Self::RootMarkers(root_markers) => paths::find_project_root(source_file, root_markers), Self::ParentOfSourceFile => Some(source_file.parent().unwrap_or(source_file)), diff --git a/crates/maple_core/src/stdio_server/diagnostics_worker.rs b/crates/maple_core/src/stdio_server/diagnostics_worker.rs index b42091088..5ba024828 100644 --- a/crates/maple_core/src/stdio_server/diagnostics_worker.rs +++ b/crates/maple_core/src/stdio_server/diagnostics_worker.rs @@ -191,6 +191,16 @@ fn update_buffer_diagnostics( .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) .is_ok(); + tracing::info!( + ?bufnr, + ?is_first_result, + "[update_buffer_diagnostics] buffer_diagnostics: {buffer_diagnostics:?}" + ); + tracing::info!( + ?bufnr, + "[update_buffer_diagnostics] new_diagnostics: {new_diagnostics:?}" + ); + let new_stats = if is_first_result { let _ = vim.exec( "clap#plugin#diagnostics#refresh_highlights", @@ -206,12 +216,12 @@ fn update_buffer_diagnostics( .filter(|d| !existing.contains(d)) .collect::>(); - followup_diagnostics.dedup(); - // Must drop the lock otherwise the deadlock occurs as // the write lock will be acquired later. drop(existing); + followup_diagnostics.dedup(); + if !followup_diagnostics.is_empty() { let _ = vim.exec( "clap#plugin#diagnostics#add_highlights", diff --git a/crates/maple_core/src/stdio_server/mod.rs b/crates/maple_core/src/stdio_server/mod.rs index 35cadc445..84edd32e7 100644 --- a/crates/maple_core/src/stdio_server/mod.rs +++ b/crates/maple_core/src/stdio_server/mod.rs @@ -165,7 +165,11 @@ fn initialize_service(vim: Vim) -> InitializedService { } if plugin_config.ctags.enable { - register_plugin(Box::new(CtagsPlugin::new(vim.clone())), None); + if crate::tools::ctags::CTAGS_BIN.is_available() { + register_plugin(Box::new(CtagsPlugin::new(vim.clone())), None); + } else { + tracing::warn!("Failed to register ctags plugin as ctags executable not found"); + } } if plugin_config.markdown.enable { diff --git a/crates/maple_core/src/stdio_server/plugin/system.rs b/crates/maple_core/src/stdio_server/plugin/system.rs index 0211be733..662e9aa2a 100644 --- a/crates/maple_core/src/stdio_server/plugin/system.rs +++ b/crates/maple_core/src/stdio_server/plugin/system.rs @@ -78,16 +78,21 @@ fn parse_vim_which_key_map(config_file: &str) -> HashMap run( async move { futures::future::join(ctags_future, gtags_future).await; diff --git a/crates/maple_core/src/tools/ctags/context_tag.rs b/crates/maple_core/src/tools/ctags/context_tag.rs index 9f86370c4..338291b01 100644 --- a/crates/maple_core/src/tools/ctags/context_tag.rs +++ b/crates/maple_core/src/tools/ctags/context_tag.rs @@ -1,7 +1,6 @@ -use crate::tools::ctags::{BufferTag, CTAGS_HAS_JSON_FEATURE}; +use crate::tools::ctags::{BufferTag, CTAGS_BIN}; use rayon::prelude::*; use std::io::Result; -use std::ops::Deref; use std::path::Path; use std::process::Stdio; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -94,7 +93,7 @@ fn find_context_tag(superset_tags: Vec, at: usize) -> Option Option { - let superset_tags = if *CTAGS_HAS_JSON_FEATURE.deref() { + let superset_tags = if CTAGS_BIN.has_json_feature() { collect_superset_context_tags_async(tokio_cmd(file, true), BufferTag::from_json_line, at) .await } else { @@ -107,7 +106,7 @@ pub async fn current_context_tag_async(file: &Path, at: usize) -> Option Option { - let superset_tags = if *CTAGS_HAS_JSON_FEATURE.deref() { + let superset_tags = if CTAGS_BIN.has_json_feature() { collect_superset_context_tags(subprocess_cmd(file, true), BufferTag::from_json_line, at) } else { collect_superset_context_tags(subprocess_cmd(file, false), BufferTag::from_raw_line, at) @@ -120,7 +119,7 @@ pub fn buffer_tags_lines( file: impl AsRef, force_raw: bool, ) -> Result> { - let (tags, max_name_len) = if *CTAGS_HAS_JSON_FEATURE.deref() && !force_raw { + let (tags, max_name_len) = if CTAGS_BIN.has_json_feature() && !force_raw { collect_buffer_tags(subprocess_cmd(file, true), BufferTag::from_json_line)? } else { collect_buffer_tags(subprocess_cmd(file, false), BufferTag::from_raw_line)? @@ -133,7 +132,7 @@ pub fn buffer_tags_lines( } pub fn fetch_buffer_tags(file: impl AsRef) -> Result> { - let (mut tags, _max_name_len) = if *CTAGS_HAS_JSON_FEATURE.deref() { + let (mut tags, _max_name_len) = if CTAGS_BIN.has_json_feature() { collect_buffer_tags(subprocess_cmd(file, true), BufferTag::from_json_line)? } else { collect_buffer_tags(subprocess_cmd(file, false), BufferTag::from_raw_line)? @@ -148,7 +147,7 @@ pub fn buffer_tag_items( file: impl AsRef, force_raw: bool, ) -> Result>> { - let (tags, max_name_len) = if *CTAGS_HAS_JSON_FEATURE.deref() && !force_raw { + let (tags, max_name_len) = if CTAGS_BIN.has_json_feature() && !force_raw { collect_buffer_tags(subprocess_cmd(file, true), BufferTag::from_json_line)? } else { collect_buffer_tags(subprocess_cmd(file, false), BufferTag::from_raw_line)? diff --git a/crates/maple_core/src/tools/ctags/mod.rs b/crates/maple_core/src/tools/ctags/mod.rs index 61301073e..cb8cb6fc1 100644 --- a/crates/maple_core/src/tools/ctags/mod.rs +++ b/crates/maple_core/src/tools/ctags/mod.rs @@ -40,8 +40,50 @@ pub static CTAGS_TAGS_DIR: Lazy = Lazy::new(|| { tags_dir }); -pub static CTAGS_EXISTS: Lazy = Lazy::new(|| { - std::process::Command::new("ctags") +pub enum CtagsBinary { + /// ctags executable exists. + Available { + /// Whether the ctags executable supports `--output-format=json`. + json_feature: bool, + }, + /// ctags executable does not exist. + NotFound, +} + +impl CtagsBinary { + pub fn is_available(&self) -> bool { + matches!(self, Self::Available { .. }) + } + + pub fn has_json_feature(&self) -> bool { + match self { + Self::Available { json_feature } => *json_feature, + Self::NotFound => false, + } + } + + pub fn ensure_json_feature(&self) -> std::io::Result<()> { + match self { + Self::Available { json_feature } => { + if *json_feature { + Ok(()) + } else { + Err(Error::new( + ErrorKind::Other, + "ctags executable is not compiled with +json feature, please recompile it.", + )) + } + } + Self::NotFound => Err(Error::new( + ErrorKind::NotFound, + "ctags executable not found", + )), + } + } +} + +pub static CTAGS_BIN: Lazy = Lazy::new(|| { + let ctags_exist = std::process::Command::new("ctags") .arg("--version") .stderr(std::process::Stdio::inherit()) .output() @@ -53,25 +95,24 @@ pub static CTAGS_EXISTS: Lazy = Lazy::new(|| { .next() .map(|line| line.starts_with("Universal Ctags")) }) - .unwrap_or(false) -}); + .unwrap_or(false); -/// If the ctags executable supports `--output-format=json`. -pub static CTAGS_HAS_JSON_FEATURE: Lazy = Lazy::new(|| { fn detect_json_feature() -> std::io::Result { let output = std::process::Command::new("ctags") .arg("--list-features") .stderr(std::process::Stdio::inherit()) .output()?; let stdout = String::from_utf8_lossy(&output.stdout); - if stdout.split('\n').any(|x| x.starts_with("json")) { - Ok(true) - } else { - Err(Error::new(ErrorKind::Other, "ctags has no +json feature")) - } + Ok(stdout.split('\n').any(|x| x.starts_with("json"))) } - detect_json_feature().unwrap_or(false) + if ctags_exist { + CtagsBinary::Available { + json_feature: detect_json_feature().unwrap_or(false), + } + } else { + CtagsBinary::NotFound + } }); /// Used to specify the language when working with `readtags`. diff --git a/crates/rpc/src/jsonrpc.rs b/crates/rpc/src/jsonrpc.rs index 60cae448e..b646fa312 100644 --- a/crates/rpc/src/jsonrpc.rs +++ b/crates/rpc/src/jsonrpc.rs @@ -40,7 +40,7 @@ impl Serialize for Version { struct VersionVisitor; -impl<'v> serde::de::Visitor<'v> for VersionVisitor { +impl serde::de::Visitor<'_> for VersionVisitor { type Value = Version; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { diff --git a/crates/tree_sitter/src/utf8_char_indices.rs b/crates/tree_sitter/src/utf8_char_indices.rs index 9168c61ec..82f1bce94 100644 --- a/crates/tree_sitter/src/utf8_char_indices.rs +++ b/crates/tree_sitter/src/utf8_char_indices.rs @@ -13,7 +13,7 @@ impl<'a> UncheckedUtf8CharIndices<'a> { } } -impl<'a> Iterator for UncheckedUtf8CharIndices<'a> { +impl Iterator for UncheckedUtf8CharIndices<'_> { type Item = (usize, char); fn next(&mut self) -> Option { @@ -49,7 +49,7 @@ impl<'a> Utf8CharIndices<'a> { } } -impl<'a> Iterator for Utf8CharIndices<'a> { +impl Iterator for Utf8CharIndices<'_> { type Item = (usize, char); fn next(&mut self) -> Option { diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 8cca5be05..a718dc2fc 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.80" +channel = "1.83"