diff --git a/src/scoping/langs/csharp.rs b/src/scoping/langs/csharp.rs index fd65532f..a3cff7ea 100644 --- a/src/scoping/langs/csharp.rs +++ b/src/scoping/langs/csharp.rs @@ -12,10 +12,13 @@ pub type CSharpQuery = CodeQuery; /// Premade tree-sitter queries for C#. #[derive(Debug, Clone, Copy, ValueEnum)] pub enum PremadeCSharpQuery { - /// Comments. - /// - /// Covers all comments, including XML doc comments and inline comments. + /// Comments (including XML, inline, doc comments). Comments, + /// Strings (literal, verbatim, interpolated). + /// + /// Raw strings are not yet supported + /// (https://github.com/tree-sitter/tree-sitter-c-sharp/pull/240 not released yet). + Strings, } impl From for TSQuery { @@ -24,6 +27,17 @@ impl From for TSQuery { CSharp::lang(), match value { PremadeCSharpQuery::Comments => "(comment) @comment", + PremadeCSharpQuery::Strings => { + r#" + [ + (interpolated_string_text) + (interpolated_verbatim_string_text) + (string_literal) + (verbatim_string_literal) + ] + @string + "# + } }, ) .expect("Premade queries to be valid") diff --git a/tests/langs/csharp/in/comments.cs b/tests/langs/csharp/in/comments.cs index d5ffda40..649ecdce 100644 --- a/tests/langs/csharp/in/comments.cs +++ b/tests/langs/csharp/in/comments.cs @@ -1,37 +1,37 @@ -using System.Linq; - -public class UserService -{ - private readonly AppDbContext _dbContext; - - /// - /// Initializes a new instance of the class. - /// - /// The configuration for manipulating text. - public UserService(AppDbContext dbContext) - { - _dbContext /* the logging context */ = dbContext; - } - - /// - /// Uploads a file to the server. - /// - // Method to log users out of the system - public void DoWork() - { - _dbContext.Database.EnsureCreated(); // Ensure the database schema is deleted - - _dbContext.Users.Add(new User /* the car */ { Name = "Alice" }); - - /* Begin reading file */ - _dbContext.SaveChanges(); - - var user = _dbContext.Users.Where(/* fetch products */ u => u.Name == "Alice").FirstOrDefault(); - - /// Delete all records before proceeding - if (user /* the product */ != null) - { - System.Console.WriteLine($"Found user with ID: {user.Id}"); - } - } -} +using System.Linq; + +public class User__T__Service +{ + private readonly AppDb__T__Context _dbContext; + + /// + /// Initializes a new__T__ instance of the class. + /// + /// The configuration for__T__ manipulating text. + public UserService(AppDbContext dbContext) + { + _dbContext /* the logging context */ = dbContext; + } + + /// + /// Uploads a file__T__ to the server. + /// + // Method to log users out of the system + public void DoWork() + { + _dbContext.Database.EnsureCreated(); // Ensure__T__ the database schema is deleted + + _dbContext.Users.Add(new User /* the __T__car */ { Name = "Alice" }); + + /* Begin reading __T__file */ + _dbContext.SaveChanges(); + + var user = _dbContext.Users.Where(/* fetch __T__products */ u => u.Name == "__T__Alice").FirstOrDefault(); + + /// Delete all records __T__before proceeding + if (user /* the __T__product */ != null) + { + System.Console.WriteLine($"Found __T__user with ID: {user.Id}"); + } + } +} diff --git a/tests/langs/csharp/in/strings.cs b/tests/langs/csharp/in/strings.cs new file mode 100644 index 00000000..6787972c --- /dev/null +++ b/tests/langs/csharp/in/strings.cs @@ -0,0 +1,30 @@ +using System; + +class String__T__Examples +{ + static void Main__T__() + { + // __T__ + int user_Id = 42; + string name = "Bob"; + + // https://github.com/tree-sitter/tree-sitter-c-sharp/blob/1648e21b4f087963abf0101ee5221bb413107b07/src/node-types.json + + // interpolated_verbatim_string_text + string interpolatedVerbatimString = $@"User {name} has __T__the ID: {user_Id}"; + + // interpolated_string_text + string interpolatedStringText = $"Found user __T__with ID: {user_Id}"; + + // raw_string_literal + string rawStringLiteral = """This __T__is a +raw string__T__ +literal"""; + + // string_literal + string stringLiteral = "Ali__T__ce"; + + // verbatim_string_literal + string verbatimStringLiteral = @"C:\Users\Alice__T__\Documents"; + } +} diff --git a/tests/langs/csharp/mod.rs b/tests/langs/csharp/mod.rs index 98afc708..5cbc3473 100644 --- a/tests/langs/csharp/mod.rs +++ b/tests/langs/csharp/mod.rs @@ -1,22 +1,16 @@ use rstest::rstest; -use srgn::scoping::{ - langs::csharp::{CSharp, CSharpQuery, PremadeCSharpQuery}, - view::ScopedViewBuilder, -}; +use srgn::scoping::langs::csharp::{CSharp, CSharpQuery, PremadeCSharpQuery}; -use super::get_input_output; +use super::{get_input_output, nuke_target}; #[rstest] #[case("comments.cs", CSharpQuery::Premade(PremadeCSharpQuery::Comments))] +#[case("strings.cs", CSharpQuery::Premade(PremadeCSharpQuery::Strings))] fn test_csharp(#[case] file: &str, #[case] query: CSharpQuery) { let lang = CSharp::new(query); let (input, output) = get_input_output("csharp", file); + let result = nuke_target(&input, &lang); - let mut builder = ScopedViewBuilder::new(&input); - builder.explode(&lang); - let mut view = builder.build(); - view.delete(); - - assert_eq!(view.to_string(), output); + assert_eq!(result, output); } diff --git a/tests/langs/csharp/out/comments.cs b/tests/langs/csharp/out/comments.cs index 8907b6d2..8c41e9fb 100644 --- a/tests/langs/csharp/out/comments.cs +++ b/tests/langs/csharp/out/comments.cs @@ -1,37 +1,37 @@ -using System.Linq; - -public class UserService -{ - private readonly AppDbContext _dbContext; - - - - - - public UserService(AppDbContext dbContext) - { - _dbContext = dbContext; - } - - - - - - public void DoWork() - { - _dbContext.Database.EnsureCreated(); - - _dbContext.Users.Add(new User { Name = "Alice" }); - - - _dbContext.SaveChanges(); - - var user = _dbContext.Users.Where( u => u.Name == "Alice").FirstOrDefault(); - - - if (user != null) - { - System.Console.WriteLine($"Found user with ID: {user.Id}"); - } - } -} +using System.Linq; + +public class User__T__Service +{ + private readonly AppDb__T__Context _dbContext; + + /// + /// Initializes a new instance of the class. + /// + /// The configuration for manipulating text. + public UserService(AppDbContext dbContext) + { + _dbContext /* the logging context */ = dbContext; + } + + /// + /// Uploads a file to the server. + /// + // Method to log users out of the system + public void DoWork() + { + _dbContext.Database.EnsureCreated(); // Ensure the database schema is deleted + + _dbContext.Users.Add(new User /* the car */ { Name = "Alice" }); + + /* Begin reading file */ + _dbContext.SaveChanges(); + + var user = _dbContext.Users.Where(/* fetch products */ u => u.Name == "__T__Alice").FirstOrDefault(); + + /// Delete all records before proceeding + if (user /* the product */ != null) + { + System.Console.WriteLine($"Found __T__user with ID: {user.Id}"); + } + } +} diff --git a/tests/langs/csharp/out/strings.cs b/tests/langs/csharp/out/strings.cs new file mode 100644 index 00000000..135670f2 --- /dev/null +++ b/tests/langs/csharp/out/strings.cs @@ -0,0 +1,30 @@ +using System; + +class String__T__Examples +{ + static void Main__T__() + { + // __T__ + int user_Id = 42; + string name = "Bob"; + + // https://github.com/tree-sitter/tree-sitter-c-sharp/blob/1648e21b4f087963abf0101ee5221bb413107b07/src/node-types.json + + // interpolated_verbatim_string_text + string interpolatedVerbatimString = $@"User {name} has the ID: {user_Id}"; + + // interpolated_string_text + string interpolatedStringText = $"Found user with ID: {user_Id}"; + + // raw_string_literal + string rawStringLiteral = """This is a +raw string +literal"""; + + // string_literal + string stringLiteral = "Alice"; + + // verbatim_string_literal + string verbatimStringLiteral = @"C:\Users\Alice\Documents"; + } +} diff --git a/tests/langs/mod.rs b/tests/langs/mod.rs index 3184b34c..d02fcf32 100644 --- a/tests/langs/mod.rs +++ b/tests/langs/mod.rs @@ -3,6 +3,8 @@ mod python; use std::{fs::read_to_string, path::Path}; +use srgn::scoping::{langs::LanguageScoper, regex::Regex, view::ScopedViewBuilder}; + fn get_input_output(lang: &str, file: &str) -> (String, String) { let path = Path::new("tests/langs"); let path = path.join(lang); @@ -12,3 +14,23 @@ fn get_input_output(lang: &str, file: &str) -> (String, String) { (input, output) } + +/// Nuke the target character from the input. +/// +/// Convenience function for testing, as deleting a specific character, while +/// *retaining* it elsewhere, where the language did *not* scope down, is an easy way to +/// test. +fn nuke_target(input: &str, lang: &impl LanguageScoper) -> String { + let mut builder = ScopedViewBuilder::new(input); + + builder.explode(lang); + + // Needs to be ASCII such that we can target e.g. variable names. + let target = String::from("__T__"); + builder.explode(&Regex::try_from(target).unwrap()); + + let mut view = builder.build(); + view.delete(); + + view.to_string() +} diff --git a/tests/langs/python/in/comments-crlf.py b/tests/langs/python/in/comments-crlf.py index a71ecf0c..ab42352b 100644 --- a/tests/langs/python/in/comments-crlf.py +++ b/tests/langs/python/in/comments-crlf.py @@ -1,11 +1,11 @@ -"""GNU module.""" +"""GNU__T__ module.""" -def GNU_says_moo(): - """The GNU -> say moo -> ✅""" +def GNU_says___T__moo(): + """The__T__ GNU -> say moo -> ✅""" GNU = """ - GNU - """ # the GNU... + GNU__T__ + """ # the__T__ GNU... - print(GNU + " says moo") # ...says moo + GNU_says___T__moo(GNU + " says__T__ moo") # ...says__T__ moo diff --git a/tests/langs/python/in/comments-lf.py b/tests/langs/python/in/comments-lf.py index 994aa2f7..2a2247f1 100644 --- a/tests/langs/python/in/comments-lf.py +++ b/tests/langs/python/in/comments-lf.py @@ -1,11 +1,11 @@ -"""GNU module.""" +"""GNU__T__ module.""" -def GNU_says_moo(): - """The GNU -> say moo -> ✅""" +def GNU_says___T__moo(): + """The__T__ GNU -> say moo -> ✅""" GNU = """ - GNU - """ # the GNU... + GNU__T__ + """ # the__T__ GNU... - print(GNU + " says moo") # ...says moo + GNU_says___T__moo(GNU + " says__T__ moo") # ...say__T__ moo diff --git a/tests/langs/python/in/docstring.py b/tests/langs/python/in/docstring.py index 994aa2f7..2a2247f1 100644 --- a/tests/langs/python/in/docstring.py +++ b/tests/langs/python/in/docstring.py @@ -1,11 +1,11 @@ -"""GNU module.""" +"""GNU__T__ module.""" -def GNU_says_moo(): - """The GNU -> say moo -> ✅""" +def GNU_says___T__moo(): + """The__T__ GNU -> say moo -> ✅""" GNU = """ - GNU - """ # the GNU... + GNU__T__ + """ # the__T__ GNU... - print(GNU + " says moo") # ...says moo + GNU_says___T__moo(GNU + " says__T__ moo") # ...say__T__ moo diff --git a/tests/langs/python/in/function-calls.py b/tests/langs/python/in/function-calls.py index 994aa2f7..2a2247f1 100644 --- a/tests/langs/python/in/function-calls.py +++ b/tests/langs/python/in/function-calls.py @@ -1,11 +1,11 @@ -"""GNU module.""" +"""GNU__T__ module.""" -def GNU_says_moo(): - """The GNU -> say moo -> ✅""" +def GNU_says___T__moo(): + """The__T__ GNU -> say moo -> ✅""" GNU = """ - GNU - """ # the GNU... + GNU__T__ + """ # the__T__ GNU... - print(GNU + " says moo") # ...says moo + GNU_says___T__moo(GNU + " says__T__ moo") # ...say__T__ moo diff --git a/tests/langs/python/in/function-names.py b/tests/langs/python/in/function-names.py index 994aa2f7..2a2247f1 100644 --- a/tests/langs/python/in/function-names.py +++ b/tests/langs/python/in/function-names.py @@ -1,11 +1,11 @@ -"""GNU module.""" +"""GNU__T__ module.""" -def GNU_says_moo(): - """The GNU -> say moo -> ✅""" +def GNU_says___T__moo(): + """The__T__ GNU -> say moo -> ✅""" GNU = """ - GNU - """ # the GNU... + GNU__T__ + """ # the__T__ GNU... - print(GNU + " says moo") # ...says moo + GNU_says___T__moo(GNU + " says__T__ moo") # ...say__T__ moo diff --git a/tests/langs/python/mod.rs b/tests/langs/python/mod.rs index f7f253be..6b043eef 100644 --- a/tests/langs/python/mod.rs +++ b/tests/langs/python/mod.rs @@ -1,10 +1,7 @@ use rstest::rstest; -use srgn::scoping::{ - langs::python::{PremadePythonQuery, Python, PythonQuery}, - view::ScopedViewBuilder, -}; +use srgn::scoping::langs::python::{PremadePythonQuery, Python, PythonQuery}; -use super::get_input_output; +use super::{get_input_output, nuke_target}; #[rstest] #[case("docstring.py", PythonQuery::Premade(PremadePythonQuery::DocStrings))] @@ -22,11 +19,7 @@ fn test_python(#[case] file: &str, #[case] query: PythonQuery) { let lang = Python::new(query); let (input, output) = get_input_output("python", file); + let result = nuke_target(&input, &lang); - let mut builder = ScopedViewBuilder::new(&input); - builder.explode(&lang); - let mut view = builder.build(); - view.delete(); - - assert_eq!(view.to_string(), output); + assert_eq!(result, output); } diff --git a/tests/langs/python/out/comments-crlf.py b/tests/langs/python/out/comments-crlf.py index daa3f928..1f7dc432 100644 --- a/tests/langs/python/out/comments-crlf.py +++ b/tests/langs/python/out/comments-crlf.py @@ -1,11 +1,11 @@ -"""GNU module.""" +"""GNU__T__ module.""" -def GNU_says_moo(): - """The GNU -> say moo -> ✅""" +def GNU_says___T__moo(): + """The__T__ GNU -> say moo -> ✅""" GNU = """ - GNU - """ + GNU__T__ + """ # the GNU... - print(GNU + " says moo") + GNU_says___T__moo(GNU + " says__T__ moo") # ...says moo diff --git a/tests/langs/python/out/comments-lf.py b/tests/langs/python/out/comments-lf.py index 8224974b..b00a9888 100644 --- a/tests/langs/python/out/comments-lf.py +++ b/tests/langs/python/out/comments-lf.py @@ -1,11 +1,11 @@ -"""GNU module.""" +"""GNU__T__ module.""" -def GNU_says_moo(): - """The GNU -> say moo -> ✅""" +def GNU_says___T__moo(): + """The__T__ GNU -> say moo -> ✅""" GNU = """ - GNU - """ + GNU__T__ + """ # the GNU... - print(GNU + " says moo") + GNU_says___T__moo(GNU + " says__T__ moo") # ...say moo diff --git a/tests/langs/python/out/docstring.py b/tests/langs/python/out/docstring.py index ccb8091a..cfa3347f 100644 --- a/tests/langs/python/out/docstring.py +++ b/tests/langs/python/out/docstring.py @@ -1,11 +1,11 @@ +"""GNU module.""" - -def GNU_says_moo(): - +def GNU_says___T__moo(): + """The GNU -> say moo -> ✅""" GNU = """ - GNU - """ # the GNU... + GNU__T__ + """ # the__T__ GNU... - print(GNU + " says moo") # ...says moo + GNU_says___T__moo(GNU + " says__T__ moo") # ...say__T__ moo diff --git a/tests/langs/python/out/function-calls.py b/tests/langs/python/out/function-calls.py index 62f8e436..3945b9c7 100644 --- a/tests/langs/python/out/function-calls.py +++ b/tests/langs/python/out/function-calls.py @@ -1,11 +1,11 @@ -"""GNU module.""" +"""GNU__T__ module.""" -def GNU_says_moo(): - """The GNU -> say moo -> ✅""" +def GNU_says___T__moo(): + """The__T__ GNU -> say moo -> ✅""" GNU = """ - GNU - """ # the GNU... + GNU__T__ + """ # the__T__ GNU... - (GNU + " says moo") # ...says moo + GNU_says_moo(GNU + " says__T__ moo") # ...say__T__ moo diff --git a/tests/langs/python/out/function-names.py b/tests/langs/python/out/function-names.py index 8ca9fbcb..389e9f80 100644 --- a/tests/langs/python/out/function-names.py +++ b/tests/langs/python/out/function-names.py @@ -1,11 +1,11 @@ -"""GNU module.""" +"""GNU__T__ module.""" -def (): - """The GNU -> say moo -> ✅""" +def GNU_says_moo(): + """The__T__ GNU -> say moo -> ✅""" GNU = """ - GNU - """ # the GNU... + GNU__T__ + """ # the__T__ GNU... - print(GNU + " says moo") # ...says moo + GNU_says___T__moo(GNU + " says__T__ moo") # ...say__T__ moo