Skip to content

Conversation

gstjepan2
Copy link
Member

@gstjepan2 gstjepan2 commented Jun 11, 2025

Fixes firefox copy paste issue where copy pasting from src adds extra newline.
Closes: #141464

@rustbot
Copy link
Collaborator

rustbot commented Jun 11, 2025

r? @GuillaumeGomez

rustbot has assigned @GuillaumeGomez.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. T-rustdoc-frontend Relevant to the rustdoc-frontend team, which will review and decide on the web UI/UX output. labels Jun 11, 2025
@rustbot
Copy link
Collaborator

rustbot commented Jun 11, 2025

Some changes occurred in HTML/CSS/JS.

cc @GuillaumeGomez, @jsha, @lolbinarycat

@rust-log-analyzer

This comment has been minimized.


if (navigator.userAgent.includes('Firefox')) {
document.addEventListener('copy', function(e){
const text = nonnull(window.getSelection()).toString().replace(/\n\n/g, '\n');
Copy link
Member

Choose a reason for hiding this comment

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

With this fix, this code:

fn foo() {}

fn bar() {}

would become:

fn foo() {}
fn bar() {}

Which definitely sounds like a new bug.

Copy link
Member Author

@gstjepan2 gstjepan2 Jun 11, 2025

Choose a reason for hiding this comment

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

You're right it it also like looks I've went with the wrong approach.

Just settings the data to text/plain seems to fix the issue

if (navigator.userAgent.includes('Firefox')) {
  document.addEventListener('copy', function(e) {
    const text = nonnull(window.getSelection()).toString();    
    nonnull(e.clipboardData).setData('text/plain', text);
    e.preventDefault();
  });
} 

I'll amend the commit with this

@rust-log-analyzer

This comment has been minimized.

Copy link
Contributor

@lolbinarycat lolbinarycat left a comment

Choose a reason for hiding this comment

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

  1. looking for the string "Firefox" is correct because safari also puts "Mozilla" in its user agent string
  2. getSelection can only return null if in a contextless environment like a detached iframe (in which case we shouldn't be getting copy events) and clipboardData can only be null for manually constructed events, so the usage of nonnull here looks correct.

It would be nice to fix this without user agent detection, but I don't see an obvious cause, the pre element only contains one set of linebreaks, and there are no extraneous whitespace nodes. The issue is the same with js enabled and disabled.

If this fixes the issue, I guess that's good.

At the very least we should probably have a comment that says why we are doing this, like "workaround for "

@gstjepan2
Copy link
Member Author

Added a workaround for comment

@GuillaumeGomez
Copy link
Member

I'm really not convinced it's the right fix. Even more considering it's only for one specific use-case. Wouldn't adding the right tags to the code viewer element be a better alternative?

@gstjepan2
Copy link
Member Author

I agree, but wouldn't that be a too big of a (breaking?) change just for copy pasting issue in firefox?

@GuillaumeGomez
Copy link
Member

I don't think so? But maybe we have something different in mind. Adding an attribute on pre.rust or on pre.rust > code to tell the web browser how to copy-paste so we don't need a JS fix should be possible, no?

@gstjepan2
Copy link
Member Author

gstjepan2 commented Jun 12, 2025

Oh gotcha, i am not aware of any clean way of doing that though, expecially without js not sure if copy paste behaviour can be modified

@lolbinarycat
Copy link
Contributor

Hold on, have we verified this is only an issue on firefox? It doesn't seem to happen in chrome but someone should probably also check safari at least.

@GuillaumeGomez
Copy link
Member

There is a bug report open in firefox about it: https://bugzilla.mozilla.org/show_bug.cgi?id=1273836

It's kinda a weird corner case apparently where they don't really what's the right behaviour.

@GuillaumeGomez
Copy link
Member

Ah interesting: if we remove the user-select: none CSS property, the backline characters are removed. Seems like there is something doable on our side then. Gonna experiment.

e.preventDefault();
});
}

Copy link
Member

Choose a reason for hiding this comment

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

So I think JS is the only way to fix this bug. However, it can be reproduced on other pages that src so the fix needs to be moved into main.js. We also need to make some changes to only tamper with the clipboard copy if we're copying from a <code> element.

So at the end of the main.js file you can add:

// This section is a bugfix for firefox: when copying text with `user-select: none`, it adds
// extra backline characters.
//
// Rustdoc issue: Workaround for https://github.com/rust-lang/rust/issues/141464
// Firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1273836
(function() {
    document.body.addEventListener('copy', event => {
        let target = event.target;
        let isInsideCode = false;
        while (target !== document.body) {
            if (target.tagName === 'CODE') {
                isInsideCode = true;
                break;
            }
            target = target.parentElement;
        }
        if (!isInsideCode) {
            return;
        }
        const selection = document.getSelection();
        nonnull(event.clipboardData).setData('text/plain', selection.toString());
        event.preventDefault();
    });
}());

I can also send a PR with the change directly, as you prefer. 😉

Copy link
Member Author

Choose a reason for hiding this comment

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

I ammended the commit with that change.

@rustbot

This comment has been minimized.

@rustbot rustbot added has-merge-commits PR has merge commits, merge with caution. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed has-merge-commits PR has merge commits, merge with caution. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 22, 2025
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

//
// Rustdoc issue: Workaround for https://github.com/rust-lang/rust/issues/141464
// Firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1273836
(function() {
Copy link
Member

Choose a reason for hiding this comment

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

It needs to be in main.js.

@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez
Copy link
Member

Almost there, just need to fix typescript errors now. :)

If you need help, don't hesitate to ask me.

@rust-log-analyzer

This comment has been minimized.

document.body.addEventListener("copy", event => {
let target = nonnull(event.target);
let isInsideCode = false;
while (target !== document.body) {
Copy link
Member

Choose a reason for hiding this comment

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

Just thought that it could potentially crash here since we never check target:

Suggested change
while (target !== document.body) {
while (target && target !== document.body) {

@GuillaumeGomez
Copy link
Member

CI is happy and code is almost all good. Just one change then I'll approve this PR. Thanks a lot!

@gstjepan2
Copy link
Member Author

pushed it.

@lolbinarycat
Copy link
Contributor

There's a few hypothetical crashes in the event handler, but since preventDefault is called last, I believe this should be fine.

@GuillaumeGomez
Copy link
Member

@lolbinarycat Absolutely. Although I do expect that it's not possible on any main browser to have this code fail (or maybe under special security levels? Unsure).

Thanks a lot for your work @gstjepan2!

@bors r+ rollup

@bors
Copy link
Collaborator

bors commented Jun 24, 2025

📌 Commit a3ede10 has been approved by GuillaumeGomez

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 24, 2025
bors added a commit that referenced this pull request Jun 24, 2025
Rollup of 9 pull requests

Successful merges:

 - #140005 (Set MSG_NOSIGNAL for UnixStream)
 - #140622 (compiletest: Improve diagnostics for line annotation mismatches)
 - #142354 (Fixes firefox copy paste issue)
 - #142695 (Port `#[rustc_skip_during_method_dispatch]` to the new attribute system)
 - #142779 (Add note about `str::split` handling of no matches.)
 - #142894 (phantom_variance_markers: fix identifier usage in macro)
 - #142928 (Fix hang in --print=file-names in bootstrap)
 - #142932 (rustdoc-json: Keep empty generic args if parenthesized)
 - #142933 (Simplify root goal API of solver a bit)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 78210a4 into rust-lang:master Jun 24, 2025
10 checks passed
@rustbot rustbot added this to the 1.90.0 milestone Jun 24, 2025
rust-timer added a commit that referenced this pull request Jun 24, 2025
Rollup merge of #142354 - gstjepan2:firefox_copy_paste_issue, r=GuillaumeGomez

Fixes firefox copy paste issue
@Noratrieb Noratrieb added the beta-nominated Nominated for backporting to the compiler in the beta channel. label Jul 13, 2025
@Noratrieb
Copy link
Member

I'm nominating this for beta backport to ensure that the Rust 1.89 docs will no longer have this issue.

@fmease
Copy link
Member

fmease commented Jul 16, 2025

Beta backport declined as per #t-rustdoc > beta-nominated: #142354 @ 💬.

Feel free to appeal over on Zulip.

@fmease fmease removed the beta-nominated Nominated for backporting to the compiler in the beta channel. label Jul 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. T-rustdoc-frontend Relevant to the rustdoc-frontend team, which will review and decide on the web UI/UX output.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Copying and pasting from rustdoc code view leaves blank lines
8 participants