Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Colorize the output of ruff format --diff #10110

Merged
merged 2 commits into from Mar 1, 2024

Conversation

senadev42
Copy link
Contributor

@senadev42 senadev42 commented Feb 24, 2024

Summary

Adds color to the output of ruff format --diff. Implemented by extracting the logic inside of towriter() and using the Colored library.

Test Plan

Tested manually in development with one of the files until colored output was achieved.

cargo run -p ruff -- format --diff crates/ruff_linter/resources/test/fixtures/pycodestyle/W29.py --no-cache

Doesn't pass the ``cargo test``` format diff tests and I'm not sure if it's because something's wrong with the implementation or if the tests need to be updated. Would like some help in that direction either way.

Related issue #9984

Copy link
Member

@MichaReiser MichaReiser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the reason why the tests fail is because the header ordering is now different:

  • before: --- before +++
  • now: +++ before ---

I believe the other issue could be that you aren't writing the hunk header (the @@)

}

unified_diff.to_writer(&mut *writer)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should re-use your new diffing for the jupyter notebook case below. But that's something that you might have planned anyway

Comment on lines 115 to 125
for hunk in unified_diff.iter_hunks() {
let hunk_str = hunk.to_string();
for line in hunk_str.lines() {
let colored_line = match line.chars().next() {
Some('+') => line.green(),
Some('-') => line.red(),
_ => line.normal(),
};
writeln!(writer, "{colored_line}")?;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: We can iterate over the changes in the hunk and use the hunk's display to avoid matching on the first character.

								// Individual hunks (section of changes)
                for hunk in unified_diff.iter_hunks() {
                    writeln!(writer, "{}", hunk.header())?;

                    // individual lines
                    for change in hunk.iter_changes() {
                        match change.tag() {
                            ChangeTag::Equal => write!(writer, " {}", change.value())?,
                            ChangeTag::Delete => write!(writer, "{}{}", "-".red(), change.value())?,
                            ChangeTag::Insert => {
                                write!(writer, "{}{}", "+".green(), change.value())?
                            }
                        }
                    }
                }

Copy link
Contributor Author

@senadev42 senadev42 Feb 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh this only colors the + and - compared to also doing change.value().green() and change.value().red() for the Delete and Insert respectively, or is only coloring the symbols the intended behavior?

Comment on lines 104 to 108
let relativized_path = if let Some(path) = path {
fs::relativize_path(path)
} else {
String::new()
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not related to your change and might be worth a separate PR but showing the same header for both add and remove doesn't feel that useful... We might want to change this that the caller needs to provide labels.

@MichaReiser
Copy link
Member

And yes, reading test failures that are diffs of diffs is extremely difficult. I had to play with the code myself to figure out what's wrong

@senadev42
Copy link
Contributor Author

I believe the reason why the tests fail is because the header ordering is now different:

  • before: --- before +++
  • now: +++ before ---

I believe the other issue could be that you aren't writing the hunk header (the @@)

Yeah the headers were flipped compared to how the built in writer was doing it. Changed that and it passes the original tests it was failing and now it's just failing these two integration tests

test diff_shows_safe_fixes_by_default ... FAILED
test diff_shows_unsafe_fixes_with_opt_in ... FAILED

diff_shows_safe_fixes_by_default:
────────────────────────────────────────────────────────────
-old snapshot
+new results
────────────┬───────────────────────────────────────────────
0 0 │ success: false␊
1 1 │ exit_code: 1␊
2 2 │ ----- stdout -----␊
3 │+--- ␊ < is green
4 │++++ ␊ < is green
3 5 │ @@ -0,0 +1 @@␊
4 6 │ +# fix from stable-test-rule-safe-fix␊
5 7 │ ␊
6 8 │ ␊
7 9 │ ----- stderr -----␊
8 │-Would fix 1 error (1 additional fix available with --unsafe-fixes). < is red
10 │+Would fix 1 error (1 additional fix available with --unsafe-fixes).␊ < is green
────────────┴───────────────────────────────────────────────

I think it has something to do with the ␊ which means linebreak stuff going on so I'll try to play around with the different types of write, writelin and '\n' (which is how the unextracted writer did it but it didn't pass linting) combinations and try to figure it out.

@MichaReiser
Copy link
Member

Interesting about the color change of the summary. That's unexpected. Maybe try again after #10127 merges. It mentions a fix related to bogus newlines

@MichaReiser
Copy link
Member

MichaReiser commented Mar 1, 2024

I didn't see any newline issues after upgrading to the latest insta version. So that seems fixed. I refactored the diff code a bit to avoid passing around writers and tested the output

image

I think this is good for merging. Thanks for working on this

@MichaReiser MichaReiser marked this pull request as ready for review March 1, 2024 08:52
@MichaReiser MichaReiser enabled auto-merge (squash) March 1, 2024 08:52
@MichaReiser MichaReiser merged commit 56d445a into astral-sh:main Mar 1, 2024
17 checks passed
Copy link
Contributor

github-actions bot commented Mar 1, 2024

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

@MichaReiser MichaReiser added the cli Related to the command-line interface label Mar 1, 2024
@senadev42
Copy link
Contributor Author

Oh yeah it looks much cleaner now, won't lie was worried about how I was going to do that since I knew enough to know it was messy but not enough to know on how to not make it so.

Also, any reason not to color the whole line (symbols + change.value()) like in the header instead of just the symbols?

(line 238, 239)

      match change.tag() {
          ChangeTag::Equal => write!(f, " {}", change.value())?,
          ChangeTag::Delete => write!(f, "{}{}", "-".red(), change.value())?,
            //                                                            ^.red()
          ChangeTag::Insert => write!(f, "{}{}", "+".green(), change.value())?,
             //                                                             ^.green()  
      }

@MichaReiser
Copy link
Member

Also, any reason not to color the whole line (symbols + change.value()) like in the header instead of just the symbols?

Uhhh no, That's not intentional. Would you be interesting in doing a follow up PR?

@senadev42
Copy link
Contributor Author

Follow up at #10183

nkxxll pushed a commit to nkxxll/ruff that referenced this pull request Mar 10, 2024
Co-authored-by: Micha Reiser <micha@reiser.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cli Related to the command-line interface
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants