feat: improve error messages with context lines

- Show 2 lines of context before and after errors (dimmed)
- Fix guessing_game.lux to be non-interactive for testing
- Use binary search simulation to demonstrate game logic

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 18:13:57 -05:00
parent 719bc77243
commit ebc0bdb109
2 changed files with 93 additions and 56 deletions

View File

@@ -1,25 +1,44 @@
// Number guessing game - demonstrates Random and Console effects // Number guessing game - demonstrates Random and Console effects
//
// Expected output:
// Welcome to the Guessing Game!
// Target number: 42
// Simulating guesses...
// Guess 50: Too high!
// Guess 25: Too low!
// Guess 37: Too low!
// Guess 43: Too high!
// Guess 40: Too low!
// Guess 41: Too low!
// Guess 42: Correct!
// Found in 7 attempts!
fn gameLoop(secret: Int, attempts: Int): Unit with {Console} = { // Game logic - check a guess against the secret
Console.print("Guess the number (1-100), attempt " + toString(attempts) + ":") fn checkGuess(guess: Int, secret: Int): String =
let guess = Console.readInt() if guess == secret then "Correct"
if guess == secret then else if guess < secret then "Too low"
Console.print("Correct! You got it in " + toString(attempts) + " attempts!") else "Too high"
else if guess < secret then {
Console.print("Too low!") // Binary search simulation to find the number
gameLoop(secret, attempts + 1) fn binarySearch(low: Int, high: Int, secret: Int, attempts: Int): Int with {Console} = {
} let mid = (low + high) / 2
else { let result = checkGuess(mid, secret)
Console.print("Too high!") Console.print("Guess " + toString(mid) + ": " + result + "!")
gameLoop(secret, attempts + 1)
} if result == "Correct" then attempts
else if result == "Too low" then binarySearch(mid + 1, high, secret, attempts + 1)
else binarySearch(low, mid - 1, secret, attempts + 1)
} }
fn main(): Unit with {Console, Random} = { fn main(): Unit with {Console} = {
Console.print("Welcome to the Guessing Game!") Console.print("Welcome to the Guessing Game!")
Console.print("I'm thinking of a number between 1 and 100...") // Use a fixed "secret" for reproducible output
let secret = Random.int(1, 100) let secret = 42
gameLoop(secret, 1) Console.print("Target number: " + toString(secret))
Console.print("Simulating guesses...")
let attempts = binarySearch(1, 100, secret, 1)
Console.print("Found in " + toString(attempts) + " attempts!")
} }
let output = run main() with {} let output = run main() with {}

View File

@@ -241,13 +241,19 @@ pub fn render_diagnostic(
colors::RESET colors::RESET
)); ));
// Source code snippet with line numbers // Source code snippet with line numbers and context
let line_num_width = end_line.to_string().len().max(4); let context_lines = 2; // Show 2 lines before and after
let start_line = line.saturating_sub(context_lines).max(1);
let end_context_line = (end_line + context_lines).min(source.lines().count());
let line_num_width = end_context_line.to_string().len().max(4);
// Show the problematic line(s) // Show context before, error lines, and context after
for line_num in line..=end_line { for line_num in start_line..=end_context_line {
if let Some(source_line) = get_source_line(source, line_num) { if let Some(source_line) = get_source_line(source, line_num) {
// Line number let is_error_line = line_num >= line && line_num <= end_line;
// Line number (dimmed for context, normal for error lines)
if is_error_line {
output.push_str(&format!( output.push_str(&format!(
"{}{:>width$}{} ", "{}{:>width$}{} ",
colors::DIM, colors::DIM,
@@ -255,12 +261,23 @@ pub fn render_diagnostic(
colors::RESET, colors::RESET,
width = line_num_width width = line_num_width
)); ));
// Source line (normal)
// Source line
output.push_str(source_line); output.push_str(source_line);
} else {
// Context lines are fully dimmed
output.push_str(&format!(
"{}{:>width$}{}{}",
colors::DIM,
line_num,
source_line,
colors::RESET,
width = line_num_width
));
}
output.push('\n'); output.push('\n');
// Underline the error span // Underline the error span (only for error lines)
if is_error_line {
let underline_start = if line_num == line { col - 1 } else { 0 }; let underline_start = if line_num == line { col - 1 } else { 0 };
let underline_end = if line_num == end_line { let underline_end = if line_num == end_line {
end_col - 1 end_col - 1
@@ -287,6 +304,7 @@ pub fn render_diagnostic(
output.push('\n'); output.push('\n');
} }
} }
}
// Error message // Error message
output.push_str(&format!("\n{}\n", diagnostic.message)); output.push_str(&format!("\n{}\n", diagnostic.message));