From 5512f448994203c61a6c20c6136e86aa929032e6 Mon Sep 17 00:00:00 2001
From: Johannes Altmanninger <aclopte@gmail.com>
Date: Sat, 13 Jan 2024 01:26:28 +0100
Subject: [PATCH] Enable doctests

They are probably not terribly useful for us but let's see what happens.

Unfortunately cargo does not properly forward the combination of "RUSTFLAGS"
and "--target" that is currently required to build with ASan [1].  Hence doctests
will fail to link on ASan builds. Let's disable doctests when ASan is active.

[1]: https://github.com/rust-lang/cargo/issues/10666 et al
---
 Cargo.toml                 |  1 -
 cmake/Tests.cmake          |  8 +++++---
 fish-rust/src/common.rs    |  8 ++++++--
 fish-rust/src/complete.rs  |  4 ----
 fish-rust/src/tinyexpr.rs  | 10 +---------
 fish-rust/src/tokenizer.rs |  2 ++
 fish-rust/src/util.rs      |  1 +
 fish-rust/src/wchar.rs     |  2 +-
 8 files changed, 16 insertions(+), 20 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index af5c696cc..9e937b3f8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -52,7 +52,6 @@ rsconf = "0.1.1"
 [lib]
 crate-type = ["rlib"]
 path = "fish-rust/src/lib.rs"
-doctest = false
 
 [[bin]]
 name = "fish"
diff --git a/cmake/Tests.cmake b/cmake/Tests.cmake
index 0ed7f7e16..c53f31c72 100644
--- a/cmake/Tests.cmake
+++ b/cmake/Tests.cmake
@@ -146,6 +146,7 @@ foreach(PEXPECT ${PEXPECTS})
   add_test_target("${PEXPECT}")
 endforeach(PEXPECT)
 
+set(cargo_test_flags)
 # Rust stuff.
 if(DEFINED ASAN)
     # Rust w/ -Zsanitizer=address requires explicitly specifying the --target triple or else linker
@@ -154,12 +155,13 @@ if(DEFINED ASAN)
         message(FATAL_ERROR "ASAN requires defining the CMake variable Rust_CARGO_TARGET to the
             intended target triple")
     endif()
-    set(cargo_target_opt "--target" ${Rust_CARGO_TARGET})
+    list(APPEND cargo_test_flags "--target" ${Rust_CARGO_TARGET})
+    list(APPEND cargo_test_flags "--lib")
 endif()
 
 add_test(
     NAME "cargo-test"
-    COMMAND env ${VARS_FOR_CARGO} cargo test ${CARGO_FLAGS} --package fish --target-dir ${rust_target_dir} ${cargo_target_opt}
+    COMMAND env ${VARS_FOR_CARGO} cargo test ${CARGO_FLAGS} --package fish --target-dir ${rust_target_dir} ${cargo_test_flags}
     WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
 )
 set_tests_properties("cargo-test" PROPERTIES SKIP_RETURN_CODE ${SKIP_RETURN_CODE})
@@ -167,7 +169,7 @@ add_test_target("cargo-test")
 
 add_test(
     NAME "cargo-test-widestring"
-    COMMAND env ${VARS_FOR_CARGO} cargo test ${CARGO_FLAGS} --package widestring-suffix --target-dir ${rust_target_dir} ${cargo_target_opt}
+    COMMAND env ${VARS_FOR_CARGO} cargo test ${CARGO_FLAGS} --package widestring-suffix --target-dir ${rust_target_dir} ${cargo_test_flags}
     WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
 )
 add_test_target("cargo-test-widestring")
diff --git a/fish-rust/src/common.rs b/fish-rust/src/common.rs
index 5b9db39e3..4ab76e691 100644
--- a/fish-rust/src/common.rs
+++ b/fish-rust/src/common.rs
@@ -1800,8 +1800,9 @@ pub fn get_executable_path(argv0: impl AsRef<Path>) -> PathBuf {
 ///
 /// ```rust
 /// use std::io::prelude::*;
+/// use fish::common::ScopeGuard;
 ///
-/// let file = std::fs::File::open("/dev/null");
+/// let file = std::fs::File::create("/dev/null").unwrap();
 /// // Create a scope guard to write to the file when the scope expires.
 /// // To be able to still use the file, shadow `file` with the ScopeGuard itself.
 /// let mut file = ScopeGuard::new(file, |file| file.write_all(b"goodbye\n").unwrap());
@@ -2000,7 +2001,10 @@ pub fn is_console_session() -> bool {
 ///
 /// # Examples
 ///
-/// ```rust
+/// ```ignore
+/// use fish::wchar::prelude::*;
+/// use fish::common::assert_sorted_by_name;
+///
 /// const COLORS: &[(&wstr, u32)] = &[
 ///     // must be in alphabetical order
 ///     (L!("blue"), 0x0000ff),
diff --git a/fish-rust/src/complete.rs b/fish-rust/src/complete.rs
index 7cb37486d..052f34a8b 100644
--- a/fish-rust/src/complete.rs
+++ b/fish-rust/src/complete.rs
@@ -2215,17 +2215,13 @@ pub fn append_completion(
 /// The command 'gcc -o' requires that a file follows it, so the `requires_param` mode is suitable.
 /// This can be done using the following line:
 ///
-/// ```
 /// complete -c gcc -s o -r
-/// ```
 ///
 /// The command 'grep -d' required that one of the strings 'read', 'skip' or 'recurse' is used. As
 /// such, it is suitable to specify that a completion requires one of them. This can be done using
 /// the following line:
 ///
-/// ```
 /// complete -c grep -s d -x -a "read skip recurse"
-/// ```
 ///
 /// - `cmd`: Command to complete.
 /// - `cmd_is_path`: If `true`, cmd will be interpreted as the absolute
diff --git a/fish-rust/src/tinyexpr.rs b/fish-rust/src/tinyexpr.rs
index fa5e049fc..bcdcbe8ba 100644
--- a/fish-rust/src/tinyexpr.rs
+++ b/fish-rust/src/tinyexpr.rs
@@ -475,7 +475,7 @@ impl<'s> State<'s> {
         };
     }
 
-    /// ```
+    /// ```text
     /// <base>   = <constant> |
     ///            <function-0> {"(" ")"} |
     ///            <function-1> <power> |
@@ -641,9 +641,7 @@ impl<'s> State<'s> {
         }
     }
 
-    /// ```
     /// <power>  = {("-" | "+")} <base>
-    /// ```
     fn power(&mut self) -> f64 {
         let mut sign = 1.0;
         while let Token::Infix(op) = self.current {
@@ -660,9 +658,7 @@ impl<'s> State<'s> {
         sign * self.base()
     }
 
-    /// ```
     /// <factor> = <power> {"^" <power>}
-    /// ```
     fn factor(&mut self) -> f64 {
         let mut ret = self.power();
 
@@ -674,9 +670,7 @@ impl<'s> State<'s> {
         ret
     }
 
-    /// ```
     /// <term>   = <factor> {("*" | "/" | "%") <factor>}
-    /// ```
     fn term(&mut self) -> f64 {
         let mut ret = self.factor();
         while let Token::Infix(op @ (Operator::Mul | Operator::Div | Operator::Rem)) = self.current
@@ -695,9 +689,7 @@ impl<'s> State<'s> {
         ret
     }
 
-    /// ```
     /// <expr>   = <term> {("+" | "-") <term>}
-    /// ```
     fn expr(&mut self) -> f64 {
         let mut ret = self.term();
         while let Token::Infix(op @ (Operator::Add | Operator::Sub)) = self.current {
diff --git a/fish-rust/src/tokenizer.rs b/fish-rust/src/tokenizer.rs
index 5584f6274..1bf289423 100644
--- a/fish-rust/src/tokenizer.rs
+++ b/fish-rust/src/tokenizer.rs
@@ -876,6 +876,7 @@ impl TryFrom<&wstr> for PipeOrRedir {
     /// Examples of supported syntaxes.
     ///    Note we are only responsible for parsing the redirection part, not 'cmd' or 'file'.
     ///
+    /// ```text
     ///     cmd | cmd        normal pipe
     ///     cmd &| cmd       normal pipe plus stderr-merge
     ///     cmd >| cmd       pipe with explicit fd
@@ -893,6 +894,7 @@ impl TryFrom<&wstr> for PipeOrRedir {
     ///     cmd &> file      redirection with stderr merge
     ///     cmd ^ file       caret (stderr) redirection, perhaps disabled via feature flags
     ///     cmd ^^ file      caret (stderr) redirection, perhaps disabled via feature flags
+    /// ```
     fn try_from(buff: &wstr) -> Result<PipeOrRedir, ()> {
         // Extract a range of leading fd.
         let mut cursor = buff.chars().take_while(|c| c.is_ascii_digit()).count();
diff --git a/fish-rust/src/util.rs b/fish-rust/src/util.rs
index b3646b078..0b4e43716 100644
--- a/fish-rust/src/util.rs
+++ b/fish-rust/src/util.rs
@@ -238,6 +238,7 @@ fn wcsfilecmp_leading_digits(a: &wstr, b: &wstr) -> (Ordering, usize, usize) {
 /// # Examples
 ///
 /// ```
+/// use fish::util::find_subslice;
 /// let haystack = b"ABC ABCDAB ABCDABCDABDE";
 ///
 /// assert_eq!(find_subslice(b"ABCDABD", haystack), Some(15));
diff --git a/fish-rust/src/wchar.rs b/fish-rust/src/wchar.rs
index 661b7c4e5..43174684c 100644
--- a/fish-rust/src/wchar.rs
+++ b/fish-rust/src/wchar.rs
@@ -32,7 +32,7 @@ pub use L;
 
 /// A proc-macro for creating wide string literals using an L *suffix*.
 ///  Example usage:
-/// ```
+/// ```ignore
 ///  #[widestrs]
 ///  pub fn func() {
 ///     let s = "hello"L; // type &'static wstr