From 77848a991ccff54f215020730fd4c3821b30ea97 Mon Sep 17 00:00:00 2001 From: Alex Povel Date: Sat, 9 Nov 2024 15:42:39 +0100 Subject: [PATCH] chore: Machine-readable output (for search mode) So far, output for search mode was oriented around human readability. It wasn't easily machine-readable, aka parsing it is difficult. This change detects whether `stdout` is a terminal and switches to a more parse-friendly output if not. While an improvement, the implementation is junk (PoC), and makes me think just providing JSON output is preferable. Then, consumers have maximum flexibility and do not have to write weird custom shell pipelines. A `jq` command would do. For JSON support, we could provide a flag `--json` (ripgrep has that too), and MAYBE perform auto-detection of TTY. For JSON support, we need a new type which encapsulates a new line found in search mode. For example, could be `struct` containing `filename`, `findings`, `ranges`, `line_number` etc., and then is serialized to a JSON line w/ serde. --- src/main.rs | 48 +++++++++++++++---- src/scoping/view.rs | 17 +++++++ ...sts__binary-data-sorted-dry-run-macos.snap | 6 +-- ...s__files-inplace-python-dry-run-macos.snap | 22 ++++----- ...i__tests__go-ignores-vendor-directory.snap | 6 +-- .../cli__tests__go-search-files-macos.snap | 14 +++--- tests/snapshots/cli__tests__go-search.snap | 12 ++--- ...nd-files-inplace-python-dry-run-macos.snap | 12 ++--- ...-scoping-inplace-python-dry-run-macos.snap | 24 ++++------ ...sts__line-numbers-outside-search-mode.snap | 6 +-- ...umbers-no-actions-outside-search-mode.snap | 6 +-- ...-and-line-numbers-outside-search-mode.snap | 4 +- .../cli__tests__python-multiple-scopes.snap | 4 +- ...cli__tests__python-search-files-macos.snap | 34 +++++++------ ...sts__python-search-stdin-across-lines.snap | 8 ++-- ..._tests__python-search-stdin-and-files.snap | 32 ++++++------- .../cli__tests__python-search-stdin.snap | 32 ++++++------- 17 files changed, 155 insertions(+), 132 deletions(-) diff --git a/src/main.rs b/src/main.rs index bc7f4202..212b5d85 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,8 +4,9 @@ //! deals with CLI argument handling, I/O, threading, and more. use std::error::Error; +use std::fmt::Write as FmtWrite; use std::fs::{self, File}; -use std::io::{self, stdout, Read, Write}; +use std::io::{self, stdout, IsTerminal, Read, Write}; use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; use std::{env, fmt}; @@ -27,6 +28,7 @@ use srgn::iterext::ParallelZipExt; use srgn::scoping::langs::LanguageScoper; use srgn::scoping::literal::{Literal, LiteralError}; use srgn::scoping::regex::{Regex, RegexError}; +use srgn::scoping::scope::{RWScope, Scope}; use srgn::scoping::view::ScopedViewBuilder; use srgn::scoping::Scoper; use tree_sitter::QueryError as TSQueryError; @@ -300,6 +302,7 @@ fn handle_actions_on_stdin( general_scoper, language_scopers, pipeline, + None, )?; stdout().lock().write_all(destination.as_bytes())?; @@ -601,6 +604,8 @@ fn process_path( return Err(PathProcessingError::InvalidFile); } + let is_terminal = stdout().is_terminal(); + debug!("Processing path: {:?}", path); let (new_contents, filesize, changed) = { @@ -613,6 +618,7 @@ fn process_path( let mut destination = String::with_capacity(source.len()); + let p = path.display().to_string(); let changed = apply( global_options, standalone_action, @@ -621,6 +627,7 @@ fn process_path( general_scoper, language_scopers, pipeline, + if is_terminal { None } else { Some(&p) }, )?; (destination, filesize, changed) @@ -631,12 +638,21 @@ fn process_path( if search_mode { if !new_contents.is_empty() { - writeln!( - stdout, - "{}\n{}", - path.display().to_string().magenta(), - &new_contents - )?; + if is_terminal { + writeln!( + stdout, + "{}\n{}", + path.display().to_string().magenta(), + &new_contents + )?; + } else { + write!( + stdout, + "{}", + // path.display().to_string().magenta(), + &new_contents + )?; + } } } else { if filesize > 0 && new_contents.is_empty() { @@ -683,6 +699,7 @@ fn process_path( /// TODO: The way this interacts with [`process_path`] etc. is just **awful** spaghetti /// of the most imperative, procedural kind. Refactor needed. #[allow(clippy::borrowed_box)] // Used throughout, not much of a pain +#[allow(clippy::too_many_arguments)] // FIXME: this function does way too much fn apply( global_options: &cli::GlobalOptions, standalone_action: StandaloneAction, @@ -693,6 +710,7 @@ fn apply( general_scoper: &Box, language_scopers: &[Box], pipeline: Pipeline<'_>, + line_prefix: Option<&str>, ) -> std::result::Result { debug!("Building view."); let mut builder = ScopedViewBuilder::new(source); @@ -743,10 +761,24 @@ fn apply( for line in lines { if !global_options.only_matching || line.has_any_in_scope() { if global_options.line_numbers { + if let Some(p) = line_prefix { + write!(destination, "{p}:").unwrap(); + } + + let x = line + .scopes_with_ranges() + .into_iter() + .filter(|(_, s)| matches!(s, RWScope(Scope::In(_, _)))) + .map(|(r, _)| (r.start, r.end)) + .map(|(start, end)| format!("{start}-{end}")) + .collect_vec() + .join(";"); + // `ColoredString` needs to be 'evaluated' to do anything; make sure // to not forget even if this is moved outside of `format!`. #[allow(clippy::to_string_in_format_args)] - destination.push_str(&format!("{}:", i.to_string().green().to_string())); + destination + .push_str(&format!("{}:{x}:", i.to_string().green().to_string())); } destination.push_str(&line.to_string()); diff --git a/src/scoping/view.rs b/src/scoping/view.rs index 25955a85..fbcc2ecd 100644 --- a/src/scoping/view.rs +++ b/src/scoping/view.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; use std::fmt; +use std::ops::Range; use itertools::Itertools; use log::{debug, trace, warn}; @@ -38,6 +39,22 @@ impl<'viewee> ScopedView<'viewee> { &self.scopes } + /// docs... + #[must_use] + pub fn scopes_with_ranges(&self) -> Vec<(Range, &RWScope<'viewee>)> { + let mut res = Vec::with_capacity(self.scopes.0.len()); + let mut start = 0; + + for scope in &self.scopes().0 { + let s: &str = scope.into(); + let end = start + s.len(); + res.push((start..end, scope)); + start = end; + } + + res + } + /// Return a builder for a view of the given input. /// /// For API discoverability. diff --git a/tests/snapshots/cli__tests__binary-data-sorted-dry-run-macos.snap b/tests/snapshots/cli__tests__binary-data-sorted-dry-run-macos.snap index 5ac7efe7..1d1adb2e 100644 --- a/tests/snapshots/cli__tests__binary-data-sorted-dry-run-macos.snap +++ b/tests/snapshots/cli__tests__binary-data-sorted-dry-run-macos.snap @@ -13,8 +13,6 @@ args: - gone stdin: ~ stdout: - - "subdir/valid-utf8\n" - - "2:unique string for precise searching: 0a1a09c8-2995-4ac5-9d60-01a0f02920e8\n" - - "2:unique string for precise searching: gone\n" - - "\n" + - "subdir/valid-utf8:2:37-73:unique string for precise searching: 0a1a09c8-2995-4ac5-9d60-01a0f02920e8\n" + - "subdir/valid-utf8:2:37-41:unique string for precise searching: gone\n" exit_code: 0 diff --git a/tests/snapshots/cli__tests__files-inplace-python-dry-run-macos.snap b/tests/snapshots/cli__tests__files-inplace-python-dry-run-macos.snap index 1f0fb0db..10687f6a 100644 --- a/tests/snapshots/cli__tests__files-inplace-python-dry-run-macos.snap +++ b/tests/snapshots/cli__tests__files-inplace-python-dry-run-macos.snap @@ -13,18 +13,12 @@ args: - baz stdin: ~ stdout: - - "1.py\n" - - "1:# This string is found and touched: foo\n" - - "1:# This string is found and touched: baz\n" - - "4:def foo(bar: int) -> int:\n" - - "4:def baz(bar: int) -> int:\n" - - "\n" - - "subdir/2.py\n" - - "1:def foo(bar: int) -> int:\n" - - "1:def baz(bar: int) -> int:\n" - - "\n" - - "subdir/subdir/3.py\n" - - "1:def foo(bar: int) -> int:\n" - - "1:def baz(bar: int) -> int:\n" - - "\n" + - "1.py:1:36-39:# This string is found and touched: foo\n" + - "1.py:1:36-39:# This string is found and touched: baz\n" + - "1.py:4:4-7:def foo(bar: int) -> int:\n" + - "1.py:4:4-7:def baz(bar: int) -> int:\n" + - "subdir/2.py:1:4-7:def foo(bar: int) -> int:\n" + - "subdir/2.py:1:4-7:def baz(bar: int) -> int:\n" + - "subdir/subdir/3.py:1:4-7:def foo(bar: int) -> int:\n" + - "subdir/subdir/3.py:1:4-7:def baz(bar: int) -> int:\n" exit_code: 0 diff --git a/tests/snapshots/cli__tests__go-ignores-vendor-directory.snap b/tests/snapshots/cli__tests__go-ignores-vendor-directory.snap index df424f35..88c9e2df 100644 --- a/tests/snapshots/cli__tests__go-ignores-vendor-directory.snap +++ b/tests/snapshots/cli__tests__go-ignores-vendor-directory.snap @@ -1,6 +1,6 @@ --- source: tests/cli.rs -expression: "CommandSnap {\n args,\n stdin: None,\n stdout: stdout.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec(),\n exit_code,\n}" +expression: "CommandSnap\n{\n args, stdin: None, stdout:\n stdout.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec(),\n exit_code,\n}" info: stderr: [] --- @@ -9,7 +9,5 @@ args: - comments stdin: ~ stdout: - - "found.go\n" - - "3:// This is found\n" - - "\n" + - "found.go:3:0-16:// This is found\n" exit_code: 0 diff --git a/tests/snapshots/cli__tests__go-search-files-macos.snap b/tests/snapshots/cli__tests__go-search-files-macos.snap index 8d5ac619..e8bc322b 100644 --- a/tests/snapshots/cli__tests__go-search-files-macos.snap +++ b/tests/snapshots/cli__tests__go-search-files-macos.snap @@ -1,8 +1,8 @@ --- source: tests/cli.rs -expression: "CommandSnap {\n args,\n stdin: stdin.map(|s|\n s.split_inclusive('\\n').map(|s| s.to_owned()).collect_vec()),\n stdout: stdout.split_inclusive('\\n').map(|s| s.to_owned()).collect_vec(),\n exit_code,\n}" +expression: "CommandSnap\n{\n args, stdin:\n stdin.map(|s|\n s.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec()), stdout:\n stdout.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec(),\n exit_code,\n}" info: - stderr: "" + stderr: [] --- args: - "--sorted" @@ -11,10 +11,8 @@ args: - "[fF]izz" stdin: ~ stdout: - - "tests/langs/go/fizzbuzz.go\n" - - "5:// fizzBuzz prints the numbers from 1 to a specified limit.\n" - - "6:// For multiples of 3, it prints \"Fizz\" instead of the number,\n" - - "8:// it prints \"FizzBuzz\".\n" - - "25:\t// Run the FizzBuzz function for numbers from 1 to 100\n" - - "\n" + - "tests/langs/go/fizzbuzz.go:5:3-7:// fizzBuzz prints the numbers from 1 to a specified limit.\n" + - "tests/langs/go/fizzbuzz.go:6:34-38:// For multiples of 3, it prints \"Fizz\" instead of the number,\n" + - "tests/langs/go/fizzbuzz.go:8:14-18:// it prints \"FizzBuzz\".\n" + - "tests/langs/go/fizzbuzz.go:25:12-16:\t// Run the FizzBuzz function for numbers from 1 to 100\n" exit_code: 0 diff --git a/tests/snapshots/cli__tests__go-search.snap b/tests/snapshots/cli__tests__go-search.snap index c7b2e6a8..5e59b8ac 100644 --- a/tests/snapshots/cli__tests__go-search.snap +++ b/tests/snapshots/cli__tests__go-search.snap @@ -1,8 +1,8 @@ --- source: tests/cli.rs -expression: "CommandSnap {\n args,\n stdin: stdin.map(|s|\n s.split_inclusive('\\n').map(|s| s.to_owned()).collect_vec()),\n stdout: stdout.split_inclusive('\\n').map(|s| s.to_owned()).collect_vec(),\n exit_code,\n}" +expression: "CommandSnap\n{\n args, stdin:\n stdin.map(|s|\n s.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec()), stdout:\n stdout.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec(),\n exit_code,\n}" info: - stderr: "" + stderr: [] --- args: - "--go" @@ -37,8 +37,8 @@ stdin: - "\tfizzBuzz(100)\n" - "}\n" stdout: - - "5:// fizzBuzz prints the numbers from 1 to a specified limit.\n" - - "6:// For multiples of 3, it prints \"Fizz\" instead of the number,\n" - - "8:// it prints \"FizzBuzz\".\n" - - "25:\t// Run the FizzBuzz function for numbers from 1 to 100\n" + - "5:3-7:// fizzBuzz prints the numbers from 1 to a specified limit.\n" + - "6:34-38:// For multiples of 3, it prints \"Fizz\" instead of the number,\n" + - "8:14-18:// it prints \"FizzBuzz\".\n" + - "25:12-16:\t// Run the FizzBuzz function for numbers from 1 to 100\n" exit_code: 0 diff --git a/tests/snapshots/cli__tests__language-scoping-and-files-inplace-python-dry-run-macos.snap b/tests/snapshots/cli__tests__language-scoping-and-files-inplace-python-dry-run-macos.snap index 1f033f4e..c3a70f58 100644 --- a/tests/snapshots/cli__tests__language-scoping-and-files-inplace-python-dry-run-macos.snap +++ b/tests/snapshots/cli__tests__language-scoping-and-files-inplace-python-dry-run-macos.snap @@ -15,12 +15,8 @@ args: - baz stdin: ~ stdout: - - "subdir/2.py\n" - - "1:def foo(bar: int) -> int:\n" - - "1:def baz(bar: int) -> int:\n" - - "\n" - - "subdir/subdir/3.py\n" - - "1:def foo(bar: int) -> int:\n" - - "1:def baz(bar: int) -> int:\n" - - "\n" + - "subdir/2.py:1:4-7:def foo(bar: int) -> int:\n" + - "subdir/2.py:1:4-7:def baz(bar: int) -> int:\n" + - "subdir/subdir/3.py:1:4-7:def foo(bar: int) -> int:\n" + - "subdir/subdir/3.py:1:4-7:def baz(bar: int) -> int:\n" exit_code: 0 diff --git a/tests/snapshots/cli__tests__language-scoping-inplace-python-dry-run-macos.snap b/tests/snapshots/cli__tests__language-scoping-inplace-python-dry-run-macos.snap index 19d175a6..74c38395 100644 --- a/tests/snapshots/cli__tests__language-scoping-inplace-python-dry-run-macos.snap +++ b/tests/snapshots/cli__tests__language-scoping-inplace-python-dry-run-macos.snap @@ -13,20 +13,12 @@ args: - baz stdin: ~ stdout: - - "1-shebanged\n" - - "9:def foo(bar: int) -> int:\n" - - "9:def baz(bar: int) -> int:\n" - - "\n" - - "1.py\n" - - "4:def foo(bar: int) -> int:\n" - - "4:def baz(bar: int) -> int:\n" - - "\n" - - "subdir/2.py\n" - - "1:def foo(bar: int) -> int:\n" - - "1:def baz(bar: int) -> int:\n" - - "\n" - - "subdir/subdir/3.py\n" - - "1:def foo(bar: int) -> int:\n" - - "1:def baz(bar: int) -> int:\n" - - "\n" + - "1-shebanged:9:4-7:def foo(bar: int) -> int:\n" + - "1-shebanged:9:4-7:def baz(bar: int) -> int:\n" + - "1.py:4:4-7:def foo(bar: int) -> int:\n" + - "1.py:4:4-7:def baz(bar: int) -> int:\n" + - "subdir/2.py:1:4-7:def foo(bar: int) -> int:\n" + - "subdir/2.py:1:4-7:def baz(bar: int) -> int:\n" + - "subdir/subdir/3.py:1:4-7:def foo(bar: int) -> int:\n" + - "subdir/subdir/3.py:1:4-7:def baz(bar: int) -> int:\n" exit_code: 0 diff --git a/tests/snapshots/cli__tests__line-numbers-outside-search-mode.snap b/tests/snapshots/cli__tests__line-numbers-outside-search-mode.snap index b2950a8b..67da3cb5 100644 --- a/tests/snapshots/cli__tests__line-numbers-outside-search-mode.snap +++ b/tests/snapshots/cli__tests__line-numbers-outside-search-mode.snap @@ -1,6 +1,6 @@ --- source: tests/cli.rs -expression: "CommandSnap {\n args,\n stdin: stdin.map(|s|\n s.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec()),\n stdout: stdout.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec(),\n exit_code,\n}" +expression: "CommandSnap\n{\n args, stdin:\n stdin.map(|s|\n s.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec()), stdout:\n stdout.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec(),\n exit_code,\n}" info: stderr: [] --- @@ -12,6 +12,6 @@ stdin: - "A\n" - B stdout: - - "1:X\n" - - "2:B" + - "1:0-1:X\n" + - "2::B" exit_code: 0 diff --git a/tests/snapshots/cli__tests__only-matching-and-line-numbers-no-actions-outside-search-mode.snap b/tests/snapshots/cli__tests__only-matching-and-line-numbers-no-actions-outside-search-mode.snap index beba2047..918bed00 100644 --- a/tests/snapshots/cli__tests__only-matching-and-line-numbers-no-actions-outside-search-mode.snap +++ b/tests/snapshots/cli__tests__only-matching-and-line-numbers-no-actions-outside-search-mode.snap @@ -1,6 +1,6 @@ --- source: tests/cli.rs -expression: "CommandSnap {\n args,\n stdin: stdin.map(|s|\n s.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec()),\n stdout: stdout.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec(),\n exit_code,\n}" +expression: "CommandSnap\n{\n args, stdin:\n stdin.map(|s|\n s.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec()), stdout:\n stdout.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec(),\n exit_code,\n}" info: stderr: [] --- @@ -11,6 +11,6 @@ stdin: - "A\n" - B stdout: - - "1:A\n" - - "2:B" + - "1:0-1:A\n" + - "2:0-1:B" exit_code: 0 diff --git a/tests/snapshots/cli__tests__only-matching-and-line-numbers-outside-search-mode.snap b/tests/snapshots/cli__tests__only-matching-and-line-numbers-outside-search-mode.snap index faece927..f8d586e9 100644 --- a/tests/snapshots/cli__tests__only-matching-and-line-numbers-outside-search-mode.snap +++ b/tests/snapshots/cli__tests__only-matching-and-line-numbers-outside-search-mode.snap @@ -1,6 +1,6 @@ --- source: tests/cli.rs -expression: "CommandSnap {\n args,\n stdin: stdin.map(|s|\n s.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec()),\n stdout: stdout.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec(),\n exit_code,\n}" +expression: "CommandSnap\n{\n args, stdin:\n stdin.map(|s|\n s.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec()), stdout:\n stdout.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec(),\n exit_code,\n}" info: stderr: [] --- @@ -13,5 +13,5 @@ stdin: - "A\n" - B stdout: - - "1:X\n" + - "1:0-1:X\n" exit_code: 0 diff --git a/tests/snapshots/cli__tests__python-multiple-scopes.snap b/tests/snapshots/cli__tests__python-multiple-scopes.snap index d02843b1..2ef68e27 100644 --- a/tests/snapshots/cli__tests__python-multiple-scopes.snap +++ b/tests/snapshots/cli__tests__python-multiple-scopes.snap @@ -1,6 +1,6 @@ --- source: tests/cli.rs -expression: "CommandSnap {\n args,\n stdin: stdin.map(|s|\n s.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec()),\n stdout: stdout.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec(),\n exit_code,\n}" +expression: "CommandSnap\n{\n args, stdin:\n stdin.map(|s|\n s.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec()), stdout:\n stdout.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec(),\n exit_code,\n}" info: stderr: [] --- @@ -16,5 +16,5 @@ stdin: - "def A(): return \"A string in a func\"\n" - "class A: pass" stdout: - - "3:def A(): return \"A string in a func\"\n" + - "3:17-18:def A(): return \"A string in a func\"\n" exit_code: 0 diff --git a/tests/snapshots/cli__tests__python-search-files-macos.snap b/tests/snapshots/cli__tests__python-search-files-macos.snap index 20db9071..bfc024c6 100644 --- a/tests/snapshots/cli__tests__python-search-files-macos.snap +++ b/tests/snapshots/cli__tests__python-search-files-macos.snap @@ -1,8 +1,8 @@ --- source: tests/cli.rs -expression: "CommandSnap {\n args,\n stdin: stdin.map(|s|\n s.split_inclusive('\\n').map(|s| s.to_owned()).collect_vec()),\n stdout: stdout.split_inclusive('\\n').map(|s| s.to_owned()).collect_vec(),\n exit_code,\n}" +expression: "CommandSnap\n{\n args, stdin:\n stdin.map(|s|\n s.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec()), stdout:\n stdout.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec(),\n exit_code,\n}" info: - stderr: "" + stderr: [] --- args: - "--sorted" @@ -11,20 +11,18 @@ args: - is stdin: ~ stdout: - - "tests/langs/python/base.py\n" - - "24: print(f\"Global test_var is now {test_var}\")\n" - - "66: print(f\"Class variable is now {cls.class_var}\")\n" - - "72: print(f\"Instance variable is {self.instance_var}\")\n" - - "86:This is a\n" - - "91:multiline_f_string = f\"\"\"This is a\n" - - "96:raw_string = r\"This is a raw string with no special treatment for \\n\"\n" - - "97:bytes_string = b\"This is a bytes string\"\n" - - "98:bytes_string = rf\"This is a raw f-string with {raw_string}\"\n" - - "118: raise ZeroDivisionError(\"Division by zero\")\n" - - "127: print(\"This will always be printed\")\n" - - "140: print(f\"Nonlocal variable is {nonlocal_var}\")\n" - - "158: print(\"test_var is greater than 5\")\n" - - "160: print(\"test_var is 5 or less\")\n" - - "165: print(f\"Counter is {counter}\")\n" - - "\n" + - "tests/langs/python/base.py:24:28-30: print(f\"Global test_var is now {test_var}\")\n" + - "tests/langs/python/base.py:66:31-33: print(f\"Class variable is now {cls.class_var}\")\n" + - "tests/langs/python/base.py:72:34-36: print(f\"Instance variable is {self.instance_var}\")\n" + - "tests/langs/python/base.py:86:2-4;5-7:This is a\n" + - "tests/langs/python/base.py:91:27-29;30-32:multiline_f_string = f\"\"\"This is a\n" + - "tests/langs/python/base.py:96:17-19;20-22:raw_string = r\"This is a raw string with no special treatment for \\n\"\n" + - "tests/langs/python/base.py:97:19-21;22-24:bytes_string = b\"This is a bytes string\"\n" + - "tests/langs/python/base.py:98:20-22;23-25:bytes_string = rf\"This is a raw f-string with {raw_string}\"\n" + - "tests/langs/python/base.py:118:40-42: raise ZeroDivisionError(\"Division by zero\")\n" + - "tests/langs/python/base.py:127:17-19: print(\"This will always be printed\")\n" + - "tests/langs/python/base.py:140:30-32: print(f\"Nonlocal variable is {nonlocal_var}\")\n" + - "tests/langs/python/base.py:158:24-26: print(\"test_var is greater than 5\")\n" + - "tests/langs/python/base.py:160:24-26: print(\"test_var is 5 or less\")\n" + - "tests/langs/python/base.py:165:24-26: print(f\"Counter is {counter}\")\n" exit_code: 0 diff --git a/tests/snapshots/cli__tests__python-search-stdin-across-lines.snap b/tests/snapshots/cli__tests__python-search-stdin-across-lines.snap index 6dca2e29..0d7aedd2 100644 --- a/tests/snapshots/cli__tests__python-search-stdin-across-lines.snap +++ b/tests/snapshots/cli__tests__python-search-stdin-across-lines.snap @@ -1,8 +1,8 @@ --- source: tests/cli.rs -expression: "CommandSnap {\n args,\n stdin: stdin.map(|s|\n s.split_inclusive('\\n').map(|s| s.to_owned()).collect_vec()),\n stdout: stdout.split_inclusive('\\n').map(|s| s.to_owned()).collect_vec(),\n exit_code,\n}" +expression: "CommandSnap\n{\n args, stdin:\n stdin.map(|s|\n s.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec()), stdout:\n stdout.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec(),\n exit_code,\n}" info: - stderr: "" + stderr: [] --- args: - "--python" @@ -221,6 +221,6 @@ stdin: - " match_statement(1)\n" - " asyncio.run(async_function())\n" stdout: - - "62: @classmethod\n" - - "63: def class_method(cls) -> None:\n" + - "62:4-17: @classmethod\n" + - "63:0-20: def class_method(cls) -> None:\n" exit_code: 0 diff --git a/tests/snapshots/cli__tests__python-search-stdin-and-files.snap b/tests/snapshots/cli__tests__python-search-stdin-and-files.snap index 8de46fd9..8ac43c57 100644 --- a/tests/snapshots/cli__tests__python-search-stdin-and-files.snap +++ b/tests/snapshots/cli__tests__python-search-stdin-and-files.snap @@ -1,8 +1,8 @@ --- source: tests/cli.rs -expression: "CommandSnap {\n args,\n stdin: stdin.map(|s|\n s.split_inclusive('\\n').map(|s| s.to_owned()).collect_vec()),\n stdout: stdout.split_inclusive('\\n').map(|s| s.to_owned()).collect_vec(),\n exit_code,\n}" +expression: "CommandSnap\n{\n args, stdin:\n stdin.map(|s|\n s.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec()), stdout:\n stdout.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec(),\n exit_code,\n}" info: - stderr: "[ERROR srgn] Detected stdin, and request for files: will use stdin and ignore files.\n" + stderr: [] --- args: - "--python" @@ -223,18 +223,18 @@ stdin: - " match_statement(1)\n" - " asyncio.run(async_function())\n" stdout: - - "24: print(f\"Global test_var is now {test_var}\")\n" - - "66: print(f\"Class variable is now {cls.class_var}\")\n" - - "72: print(f\"Instance variable is {self.instance_var}\")\n" - - "86:This is a\n" - - "91:multiline_f_string = f\"\"\"This is a\n" - - "96:raw_string = r\"This is a raw string with no special treatment for \\n\"\n" - - "97:bytes_string = b\"This is a bytes string\"\n" - - "98:bytes_string = rf\"This is a raw f-string with {raw_string}\"\n" - - "118: raise ZeroDivisionError(\"Division by zero\")\n" - - "127: print(\"This will always be printed\")\n" - - "140: print(f\"Nonlocal variable is {nonlocal_var}\")\n" - - "158: print(\"test_var is greater than 5\")\n" - - "160: print(\"test_var is 5 or less\")\n" - - "165: print(f\"Counter is {counter}\")\n" + - "24:28-30: print(f\"Global test_var is now {test_var}\")\n" + - "66:31-33: print(f\"Class variable is now {cls.class_var}\")\n" + - "72:34-36: print(f\"Instance variable is {self.instance_var}\")\n" + - "86:2-4;5-7:This is a\n" + - "91:27-29;30-32:multiline_f_string = f\"\"\"This is a\n" + - "96:17-19;20-22:raw_string = r\"This is a raw string with no special treatment for \\n\"\n" + - "97:19-21;22-24:bytes_string = b\"This is a bytes string\"\n" + - "98:20-22;23-25:bytes_string = rf\"This is a raw f-string with {raw_string}\"\n" + - "118:40-42: raise ZeroDivisionError(\"Division by zero\")\n" + - "127:17-19: print(\"This will always be printed\")\n" + - "140:30-32: print(f\"Nonlocal variable is {nonlocal_var}\")\n" + - "158:24-26: print(\"test_var is greater than 5\")\n" + - "160:24-26: print(\"test_var is 5 or less\")\n" + - "165:24-26: print(f\"Counter is {counter}\")\n" exit_code: 0 diff --git a/tests/snapshots/cli__tests__python-search-stdin.snap b/tests/snapshots/cli__tests__python-search-stdin.snap index 652dc65e..b54088ee 100644 --- a/tests/snapshots/cli__tests__python-search-stdin.snap +++ b/tests/snapshots/cli__tests__python-search-stdin.snap @@ -1,8 +1,8 @@ --- source: tests/cli.rs -expression: "CommandSnap {\n args,\n stdin: stdin.map(|s|\n s.split_inclusive('\\n').map(|s| s.to_owned()).collect_vec()),\n stdout: stdout.split_inclusive('\\n').map(|s| s.to_owned()).collect_vec(),\n exit_code,\n}" +expression: "CommandSnap\n{\n args, stdin:\n stdin.map(|s|\n s.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec()), stdout:\n stdout.split_inclusive('\\n').map(ToOwned::to_owned).collect_vec(),\n exit_code,\n}" info: - stderr: "" + stderr: [] --- args: - "--python" @@ -221,18 +221,18 @@ stdin: - " match_statement(1)\n" - " asyncio.run(async_function())\n" stdout: - - "24: print(f\"Global test_var is now {test_var}\")\n" - - "66: print(f\"Class variable is now {cls.class_var}\")\n" - - "72: print(f\"Instance variable is {self.instance_var}\")\n" - - "86:This is a\n" - - "91:multiline_f_string = f\"\"\"This is a\n" - - "96:raw_string = r\"This is a raw string with no special treatment for \\n\"\n" - - "97:bytes_string = b\"This is a bytes string\"\n" - - "98:bytes_string = rf\"This is a raw f-string with {raw_string}\"\n" - - "118: raise ZeroDivisionError(\"Division by zero\")\n" - - "127: print(\"This will always be printed\")\n" - - "140: print(f\"Nonlocal variable is {nonlocal_var}\")\n" - - "158: print(\"test_var is greater than 5\")\n" - - "160: print(\"test_var is 5 or less\")\n" - - "165: print(f\"Counter is {counter}\")\n" + - "24:28-30: print(f\"Global test_var is now {test_var}\")\n" + - "66:31-33: print(f\"Class variable is now {cls.class_var}\")\n" + - "72:34-36: print(f\"Instance variable is {self.instance_var}\")\n" + - "86:2-4;5-7:This is a\n" + - "91:27-29;30-32:multiline_f_string = f\"\"\"This is a\n" + - "96:17-19;20-22:raw_string = r\"This is a raw string with no special treatment for \\n\"\n" + - "97:19-21;22-24:bytes_string = b\"This is a bytes string\"\n" + - "98:20-22;23-25:bytes_string = rf\"This is a raw f-string with {raw_string}\"\n" + - "118:40-42: raise ZeroDivisionError(\"Division by zero\")\n" + - "127:17-19: print(\"This will always be printed\")\n" + - "140:30-32: print(f\"Nonlocal variable is {nonlocal_var}\")\n" + - "158:24-26: print(\"test_var is greater than 5\")\n" + - "160:24-26: print(\"test_var is 5 or less\")\n" + - "165:24-26: print(f\"Counter is {counter}\")\n" exit_code: 0