Skip to content

Fixes firefox copy paste issue #142354

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

Merged
merged 1 commit into from
Jun 24, 2025

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.

@@ -206,6 +206,15 @@ const handleSrcHighlight = (function() {
};
}());

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

@gstjepan2 gstjepan2 force-pushed the firefox_copy_paste_issue branch from 3624543 to 17ce882 Compare June 11, 2025 11:41
@rust-log-analyzer

This comment has been minimized.

@gstjepan2 gstjepan2 force-pushed the firefox_copy_paste_issue branch from 17ce882 to bb5aabf Compare June 11, 2025 12:14
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 gstjepan2 force-pushed the firefox_copy_paste_issue branch from bb5aabf to 92bc271 Compare June 12, 2025 12:36
@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. labels Jun 22, 2025
@gstjepan2 gstjepan2 force-pushed the firefox_copy_paste_issue branch from ca39813 to 92bc271 Compare June 22, 2025 08:00
@rustbot rustbot 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
@gstjepan2 gstjepan2 force-pushed the firefox_copy_paste_issue branch 2 times, most recently from 71e24e8 to b0a8219 Compare June 22, 2025 08:01
@gstjepan2 gstjepan2 force-pushed the firefox_copy_paste_issue branch 2 times, most recently from 792e55b to 4469a74 Compare June 22, 2025 08:02
@rust-log-analyzer

This comment has been minimized.

@gstjepan2 gstjepan2 force-pushed the firefox_copy_paste_issue branch from 4469a74 to 4adaf0a Compare June 22, 2025 09:25
@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.

@gstjepan2 gstjepan2 force-pushed the firefox_copy_paste_issue branch 2 times, most recently from c67264f to 36b9d73 Compare June 23, 2025 00:17
@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.

@gstjepan2 gstjepan2 force-pushed the firefox_copy_paste_issue branch 2 times, most recently from 9369751 to 5ed0173 Compare June 23, 2025 11:36
@rust-log-analyzer

This comment has been minimized.

@gstjepan2 gstjepan2 force-pushed the firefox_copy_paste_issue branch from 5ed0173 to 96255ec Compare June 23, 2025 12:06
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 gstjepan2 force-pushed the firefox_copy_paste_issue branch from 96255ec to a3ede10 Compare June 23, 2025 14:39
@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
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
6 participants