Ruby: add some links to diagnostic messages

This commit is contained in:
Arthur Baars
2023-03-07 17:55:13 +01:00
parent 78a802359e
commit 858aa9ae63
4 changed files with 75 additions and 39 deletions

View File

@@ -214,6 +214,12 @@ fn longest_backtick_sequence_length(text: &str) -> usize {
} }
result result
} }
pub enum Arg<'a> {
Code(&'a str),
Link(&'a str, &'a str),
None,
}
impl DiagnosticMessage { impl DiagnosticMessage {
pub fn full_error_message(&self) -> String { pub fn full_error_message(&self) -> String {
match &self.location { match &self.location {
@@ -236,28 +242,42 @@ impl DiagnosticMessage {
self self
} }
pub fn message(&mut self, text: &str, args: &[&str]) -> &mut Self { pub fn message(&mut self, text: &str, args: &[Arg]) -> &mut Self {
let parts = text.split("{}"); let parts = text.split("{}");
let args = args.iter().chain(std::iter::repeat(&"")); let args = args.iter().chain(std::iter::repeat(&Arg::None));
let mut plain = String::with_capacity(2 * text.len()); let mut plain = String::with_capacity(2 * text.len());
let mut markdown = String::with_capacity(2 * text.len()); let mut markdown = String::with_capacity(2 * text.len());
for (p, a) in parts.zip(args) { for (p, a) in parts.zip(args) {
plain.push_str(p); plain.push_str(p);
plain.push_str(a);
markdown.push_str(p); markdown.push_str(p);
if a.len() > 0 { match a {
let count = longest_backtick_sequence_length(a) + 1; Arg::Code(t) => {
plain.push_str(t);
if t.len() > 0 {
let count = longest_backtick_sequence_length(t) + 1;
markdown.push_str(&"`".repeat(count)); markdown.push_str(&"`".repeat(count));
if count > 1 { if count > 1 {
markdown.push_str(" "); markdown.push_str(" ");
} }
markdown.push_str(a); markdown.push_str(t);
if count > 1 { if count > 1 {
markdown.push_str(" "); markdown.push_str(" ");
} }
markdown.push_str(&"`".repeat(count)); markdown.push_str(&"`".repeat(count));
} }
} }
Arg::Link(text, url) => {
plain.push_str(text);
self.help_link(url);
markdown.push_str("[");
markdown.push_str(text);
markdown.push_str("](");
markdown.push_str(url);
markdown.push_str(")");
}
Arg::None => {}
}
}
self.text(&plain); self.text(&plain);
self.markdown(&markdown); self.markdown(&markdown);
self self
@@ -323,14 +343,14 @@ fn test_message() {
let mut m = DiagnosticLoggers::new("foo") let mut m = DiagnosticLoggers::new("foo")
.logger() .logger()
.new_entry("id", "name"); .new_entry("id", "name");
m.message("hello: {}", &["hello"]); m.message("hello: {}", &[Arg::Code("hello")]);
assert_eq!("hello: hello", m.plaintext_message); assert_eq!("hello: hello", m.plaintext_message);
assert_eq!("hello: `hello`", m.markdown_message); assert_eq!("hello: `hello`", m.markdown_message);
let mut m = DiagnosticLoggers::new("foo") let mut m = DiagnosticLoggers::new("foo")
.logger() .logger()
.new_entry("id", "name"); .new_entry("id", "name");
m.message("hello with backticks: {}", &["oh `hello`!"]); m.message("hello with backticks: {}", &[Arg::Code("oh `hello`!")]);
assert_eq!("hello with backticks: oh `hello`!", m.plaintext_message); assert_eq!("hello with backticks: oh `hello`!", m.plaintext_message);
assert_eq!( assert_eq!(
"hello with backticks: `` oh `hello`! ``", "hello with backticks: `` oh `hello`! ``",

View File

@@ -277,7 +277,7 @@ impl<'a> Visitor<'a> {
fn record_parse_error_for_node( fn record_parse_error_for_node(
&mut self, &mut self,
message: &str, message: &str,
args: &[&str], args: &[diagnostics::Arg],
node: Node, node: Node,
status_page: bool, status_page: bool,
) { ) {
@@ -306,8 +306,8 @@ impl<'a> Visitor<'a> {
fn enter_node(&mut self, node: Node) -> bool { fn enter_node(&mut self, node: Node) -> bool {
if node.is_missing() { if node.is_missing() {
self.record_parse_error_for_node( self.record_parse_error_for_node(
"A parse error occurred (expected {} symbol). Check the syntax of the file. If the file is invalid, correct the error or exclude the file from analysis.", "A parse error occurred (expected {} symbol). Check the syntax of the file. If the file is invalid, correct the error or {} the file from analysis.",
&[node.kind()], &[diagnostics::Arg::Code(node.kind()), diagnostics::Arg::Link("exclude", "https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/customizing-code-scanning")],
node, node,
true, true,
); );
@@ -315,8 +315,8 @@ impl<'a> Visitor<'a> {
} }
if node.is_error() { if node.is_error() {
self.record_parse_error_for_node( self.record_parse_error_for_node(
"A parse error occurred. Check the syntax of the file. If the file is invalid, correct the error or exclude the file from analysis.", "A parse error occurred. Check the syntax of the file. If the file is invalid, correct the error or {} the file from analysis.",
&[], &[diagnostics::Arg::Link("exclude", "https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/customizing-code-scanning")],
node, node,
true, true,
); );
@@ -407,7 +407,10 @@ impl<'a> Visitor<'a> {
.new_entry("parse-error", "Parse error") .new_entry("parse-error", "Parse error")
.severity(diagnostics::Severity::Error) .severity(diagnostics::Severity::Error)
.location(self.path, start_line, start_column, end_line, end_column) .location(self.path, start_line, start_column, end_line, end_column)
.message("Unknown table type: {}", &[node.kind()]), .message(
"Unknown table type: {}",
&[diagnostics::Arg::Code(node.kind())],
),
); );
valid = false; valid = false;
@@ -458,10 +461,10 @@ impl<'a> Visitor<'a> {
self.record_parse_error_for_node( self.record_parse_error_for_node(
"Type mismatch for field {}::{} with type {} != {}", "Type mismatch for field {}::{} with type {} != {}",
&[ &[
node.kind(), diagnostics::Arg::Code(node.kind()),
child_node.field_name.unwrap_or("child"), diagnostics::Arg::Code(child_node.field_name.unwrap_or("child")),
&format!("{:?}", child_node.type_name), diagnostics::Arg::Code(&format!("{:?}", child_node.type_name)),
&format!("{:?}", field.type_info), diagnostics::Arg::Code(&format!("{:?}", field.type_info)),
], ],
*node, *node,
false, false,
@@ -471,9 +474,9 @@ impl<'a> Visitor<'a> {
self.record_parse_error_for_node( self.record_parse_error_for_node(
"Value for unknown field: {}::{} and type {}", "Value for unknown field: {}::{} and type {}",
&[ &[
node.kind(), diagnostics::Arg::Code(node.kind()),
&child_node.field_name.unwrap_or("child"), diagnostics::Arg::Code(&child_node.field_name.unwrap_or("child")),
&format!("{:?}", child_node.type_name), diagnostics::Arg::Code(&format!("{:?}", child_node.type_name)),
], ],
*node, *node,
false, false,
@@ -512,7 +515,10 @@ impl<'a> Visitor<'a> {
if !*has_index && index > 0 { if !*has_index && index > 0 {
self.record_parse_error_for_node( self.record_parse_error_for_node(
"Too many values for field: {}::{}", "Too many values for field: {}::{}",
&[node.kind(), table_name], &[
diagnostics::Arg::Code(node.kind()),
diagnostics::Arg::Code(table_name),
],
*node, *node,
false, false,
); );
@@ -629,8 +635,11 @@ fn location_for(visitor: &mut Visitor, n: Node) -> (usize, usize, usize, usize)
.diagnostics_writer .diagnostics_writer
.new_entry("internal-error", "Internal error") .new_entry("internal-error", "Internal error")
.message( .message(
"Cannot correct end column value: end_byte index {} is not in range [1,{}]", "Cannot correct end column value: end_byte index {} is not in range [1,{}].",
&[&index.to_string(), &source.len().to_string()], &[
diagnostics::Arg::Code(&index.to_string()),
diagnostics::Arg::Code(&source.len().to_string()),
],
) )
.severity(diagnostics::Severity::Error), .severity(diagnostics::Severity::Error),
); );

View File

@@ -74,7 +74,7 @@ fn main() -> std::io::Result<()> {
main_thread_logger.write( main_thread_logger.write(
main_thread_logger main_thread_logger
.new_entry("configuration-error", "Configuration error") .new_entry("configuration-error", "Configuration error")
.message("{}; defaulting to 1 thread.", &[&e]) .message("{}; defaulting to 1 thread.", &[diagnostics::Arg::Code(&e)])
.severity(diagnostics::Severity::Warning), .severity(diagnostics::Severity::Warning),
); );
1 1
@@ -95,7 +95,7 @@ fn main() -> std::io::Result<()> {
main_thread_logger.write( main_thread_logger.write(
main_thread_logger main_thread_logger
.new_entry("configuration-error", "Configuration error") .new_entry("configuration-error", "Configuration error")
.message("{}; using gzip.", &[&e]) .message("{}; using gzip.", &[diagnostics::Arg::Code(&e)])
.severity(diagnostics::Severity::Warning), .severity(diagnostics::Severity::Warning),
); );
trap::Compression::Gzip trap::Compression::Gzip
@@ -203,11 +203,15 @@ fn main() -> std::io::Result<()> {
) )
.file(&path.to_string_lossy()) .file(&path.to_string_lossy())
.message( .message(
"Could not decode the file contents as {}: {}. The contents of the file must match the character encoding specified in the {} directive.", "Could not decode the file contents as {}: {}. The contents of the file must match the character encoding specified in the {} {}.",
&[&encoding_name, &msg, "encoding:"], &[
diagnostics::Arg::Code(&encoding_name),
diagnostics::Arg::Code(&msg),
diagnostics::Arg::Code("encoding:"),
diagnostics::Arg::Link("directive", "https://docs.ruby-lang.org/en/master/syntax/comments_rdoc.html#label-encoding+Directive")
],
) )
.status_page() .status_page()
.help_link("https://docs.ruby-lang.org/en/master/syntax/comments_rdoc.html#label-encoding+Directive")
.severity(diagnostics::Severity::Warning), .severity(diagnostics::Severity::Warning),
); );
} }
@@ -219,11 +223,14 @@ fn main() -> std::io::Result<()> {
.new_entry("unknown-character-encoding", "Unknown character encoding") .new_entry("unknown-character-encoding", "Unknown character encoding")
.file(&path.to_string_lossy()) .file(&path.to_string_lossy())
.message( .message(
"Unknown character encoding {} in {} directive.", "Unknown character encoding {} in {} {}.",
&[&encoding_name, "#encoding:"], &[
diagnostics::Arg::Code(&encoding_name),
diagnostics::Arg::Code("#encoding:"),
diagnostics::Arg::Link("directive", "https://docs.ruby-lang.org/en/master/syntax/comments_rdoc.html#label-encoding+Directive")
],
) )
.status_page() .status_page()
.help_link("https://docs.ruby-lang.org/en/master/syntax/comments_rdoc.html#label-encoding+Directive")
.severity(diagnostics::Severity::Warning), .severity(diagnostics::Severity::Warning),
); );
} }

View File

@@ -1 +1 @@
| src/not_ruby.rb:5:25:5:26 | A parse error occurred. Check the syntax of the file using the ruby -c command. If the file is invalid, correct the error or exclude the file from analysis. | Extraction failed in src/not_ruby.rb with error A parse error occurred. Check the syntax of the file using the ruby -c command. If the file is invalid, correct the error or exclude the file from analysis. | 2 | | src/not_ruby.rb:5:25:5:26 | A parse error occurred. Check the syntax of the file. If the file is invalid, correct the error or exclude the file from analysis. | Extraction failed in src/not_ruby.rb with error A parse error occurred. Check the syntax of the file. If the file is invalid, correct the error or exclude the file from analysis. | 2 |