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

Fix tabs having a fixed width internally #5039

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

karyon
Copy link
Contributor

@karyon karyon commented Oct 22, 2021

Ref #4968. Tabs were always counted to have a width of config.tab_spaces.
Since they actually can have less than that depending on the line's
previous contents, rustfmt would sometimes complain about the line
length even if the line did actually fit.

Ref rust-lang#4968. Tabs were always counted to have a width of config.tab_spaces.
Since they actually can have less than that depending on the line's
previous contents, rustfmt would sometimes complain about the line
length even if the line did actually fit.
@MitMaro
Copy link

MitMaro commented Oct 23, 2021

Looks like this still fails if there is more than one tab character in a line.

@calebcartwright
Copy link
Member

@MitMaro - thanks for sharing! sounds straightforward enough, but do you have a snippet you'd be willing to share? that makes adding a corresponding test case a bit easier

@MitMaro
Copy link

MitMaro commented Oct 25, 2021

Here's a test case (based on the one above) that still causes a panic:

// rustfmt-error_on_unformatted: true
// rustfmt-error_on_line_overflow: true

// Part of #4968. This line has a width of 100, so it should be fine, but rustfmt panicked.
fn panic_with_tabs() {
    let a = "tab here:		Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonu est \
             est, consetetur sadipscing";
}

Here's the stack:

thread '<unnamed>' panicked at 'SourceAnnotation range `(100, 104)` is bigger than source length `100`', /home/mitmaro/.cargo/registry/src/gitpro.ttaallkk.top-1ecc6299db9ec823/annotate-snippets-0.8.0/src/display_list/from_snippet.rs:273:9
stack backtrace:
   0: rust_begin_unwind
             at /rustc/1af55d19c7a9189374d89472f97dc119659bb67e/library/std/src/panicking.rs:517:5
   1: std::panicking::begin_panic_fmt
             at /rustc/1af55d19c7a9189374d89472f97dc119659bb67e/library/std/src/panicking.rs:460:5
   2: annotate_snippets::display_list::from_snippet::format_body
             at /home/mitmaro/.cargo/registry/src/gitpro.ttaallkk.top-1ecc6299db9ec823/annotate-snippets-0.8.0/src/display_list/from_snippet.rs:273:9
   3: annotate_snippets::display_list::from_snippet::format_slice
             at /home/mitmaro/.cargo/registry/src/gitpro.ttaallkk.top-1ecc6299db9ec823/annotate-snippets-0.8.0/src/display_list/from_snippet.rs:114:20
   4: annotate_snippets::display_list::from_snippet::<impl core::convert::From<annotate_snippets::snippet::Snippet> for annotate_snippets::display_list::structs::DisplayList>::from
             at /home/mitmaro/.cargo/registry/src/gitpro.ttaallkk.top-1ecc6299db9ec823/annotate-snippets-0.8.0/src/display_list/from_snippet.rs:487:30
   5: <rustfmt_nightly::format_report_formatter::FormatReportFormatter as core::fmt::Display>::fmt
             at ./src/format_report_formatter.rs:95:37
   6: core::fmt::write
             at /rustc/1af55d19c7a9189374d89472f97dc119659bb67e/library/core/src/fmt/mod.rs:1163:17
   7: std::io::Write::write_fmt
             at /rustc/1af55d19c7a9189374d89472f97dc119659bb67e/library/std/src/io/mod.rs:1696:15
   8: std::io::stdio::print_to::{{closure}}::{{closure}}
             at /rustc/1af55d19c7a9189374d89472f97dc119659bb67e/library/std/src/io/stdio.rs:1187:25
   9: core::option::Option<T>::map
             at /rustc/1af55d19c7a9189374d89472f97dc119659bb67e/library/core/src/option.rs:848:29
  10: std::io::stdio::print_to::{{closure}}
             at /rustc/1af55d19c7a9189374d89472f97dc119659bb67e/library/std/src/io/stdio.rs:1186:13
  11: std::thread::local::LocalKey<T>::try_with
             at /rustc/1af55d19c7a9189374d89472f97dc119659bb67e/library/std/src/thread/local.rs:399:16
  12: std::io::stdio::print_to
             at /rustc/1af55d19c7a9189374d89472f97dc119659bb67e/library/std/src/io/stdio.rs:1182:12
  13: std::io::stdio::_print
             at /rustc/1af55d19c7a9189374d89472f97dc119659bb67e/library/std/src/io/stdio.rs:1209:5
  14: rustfmt_nightly::test::check_files
             at ./src/test/mod.rs:540:17
  15: rustfmt_nightly::test::idempotence_tests::{{closure}}
             at ./src/test/mod.rs:320:40

@MitMaro
Copy link

MitMaro commented Oct 25, 2021

Another test case, and one I reduced from one of my projects that still causes a crash in rustfmt is leading tabs with hard_tabs: true.

// rustfmt-error_on_unformatted: true
// rustfmt-error_on_line_overflow: true
// rustfmt-hard_tabs: true

fn panic_with_tabs() {
	let a = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
}
thread '<unnamed>' panicked at 'SourceAnnotation range `(100, 105)` is bigger than source length `102`', /home/mitmaro/.cargo/registry/src/gitpro.ttaallkk.top-1ecc6299db9ec823/annotate-snippets-0.8.0/src/display_list/from_snippet.rs:273:9

@karyon
Copy link
Contributor Author

karyon commented Oct 26, 2021

Right. I didn't fix the entire bug, only those (few) cases where the line would actually fit into the width limit. See my comment here: #4968 (comment)

@@ -559,7 +559,7 @@ impl<'a> FormatLines<'a> {
fn char(&mut self, c: char, kind: FullCodeCharKind) {
self.newline_count = 0;
self.line_len += if c == '\t' {
self.config.tab_spaces()
self.config.tab_spaces() - self.line_len % self.config.tab_spaces()
} else {
1
Copy link
Contributor

Choose a reason for hiding this comment

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

This 1 can also cause issues with non-ascii idents. Could be c.len_utf8().

Copy link
Contributor

Choose a reason for hiding this comment

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

Another possible fix for tabs is to use self.line_buffer.push_str(&" ".repeat(self.config.tab_spaces())). Not sure which is correct.

Raekye added a commit to Raekye/rustfmt that referenced this pull request Dec 7, 2022
* Internally, rustfmt preserves tabs and counts them as multiple
  characters (based on configuration).
* The annoted_snippet dependency counts tabs as 1 character.
* If rustfmt produces an error on a line containing tabs,
  annotated_snippet may think that the error is out of range and panic.
* Have rustfmt internally replace tabs with the corresponding number of
  spaces, so that columns can be counted unambiguously.
* This change is based on PR rust-lang#5039 by karyon, but with the code review
  suggestions by camsteffen.
Raekye added a commit to Raekye/rustfmt that referenced this pull request Aug 27, 2023
* Internally, rustfmt preserves tabs and counts them as multiple
  characters (based on configuration).
* The annotated_snippet dependency always counts tabs as 1 character.
* If rustfmt tries to display an error on a line containing tabs,
  the indicies are mismatched.
* In the extreme case, annotated_snippet may try to access out-of-range
  indices, and panic.
* This change is based on the code review by camsteffen on PR rust-lang#5039 by
  karyon: have rustfmt internally replace tabs with the corresponding
  number of spaces, so that columns/indices in the buffer passed to
  annotated_snippet are counted (unambiguously and) the same.
Raekye added a commit to Raekye/rustfmt that referenced this pull request Dec 3, 2023
* Internally, rustfmt preserves tabs and counts them as multiple
  characters (based on configuration).
* The annotated_snippet dependency always counts tabs as 1 character.
* If rustfmt tries to display an error on a line containing tabs,
  the indicies are mismatched.
* In the extreme case, annotated_snippet may try to access out-of-range
  indices, and panic.
* This change is based on the code review by camsteffen on PR rust-lang#5039 by
  karyon: have rustfmt internally replace tabs with the corresponding
  number of spaces, so that columns/indices in the buffer passed to
  annotated_snippet are counted (unambiguously and) the same.
Raekye added a commit to Raekye/rustfmt that referenced this pull request Dec 30, 2023
* This change is based on the code review by camsteffen on PR
  rust-lang#5039 by karyon: have rustfmt internally replace tabs with
  the corresponding number of spaces, so that columns/indices in the
  buffer passed to annotated_snippet are counted unambiguously.
@drahnr
Copy link

drahnr commented Aug 2, 2024

@karyon @camsteffen gentle ping

@camsteffen
Copy link
Contributor

@drahnr neither of us can do anything to advance this PR AFAICT. The maintainers have to action on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants