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 paste with new line #2696

Merged
merged 2 commits into from
Nov 7, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ import {
CompletionContext,
completionKeymap,
} from '@codemirror/autocomplete';
import { EditorState, Extension, StateEffect, StateField } from '@codemirror/state';
import {
ChangeSpec,
EditorState,
Extension,
StateEffect,
StateField,
} from '@codemirror/state';
import {
Decoration,
DecorationSet,
Expand Down Expand Up @@ -126,8 +132,28 @@ export class XInputComponent implements AfterViewInit, ControlValueAccessor {
},
},
});

const filterNewLine = EditorState.transactionFilter.of((tr) => {
Copy link

Choose a reason for hiding this comment

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

issue (complexity): Consider simplifying the newline filtering logic by using string replacement instead of iterative change tracking

The current implementation is unnecessarily complex with nested iterations and change tracking. Here's a simpler approach that maintains the same functionality:

const filterNewLine = EditorState.transactionFilter.of((tr) => {
  if (tr.changes.empty) return tr;

  if (tr.isUserEvent('input.paste')) {
    // For paste events, replace newlines with spaces
    const changes = [{
      from: 0,
      to: tr.newDoc.length,
      insert: tr.newDoc.toString().replace(/\n/g, ' ')
    }];
    return [{ changes }];
  }

  // Block multi-line input from other sources
  return tr.newDoc.lines > 1 ? [] : [tr];
});

This achieves the same result more clearly by:

  1. Handling paste events with a simple string replacement
  2. Blocking other multi-line input directly
  3. Eliminating the need for nested iterations and change tracking

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's brilliant! It's a much simpler logic to the problem. I only had to tweak a bit but most of the logic worked!

return tr.newDoc.lines > 1 ? [] : [tr];
if (tr.changes.empty) return tr;
Copy link

Choose a reason for hiding this comment

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

suggestion (code-quality): Use block braces for ifs, whiles, etc. (use-braces)

Suggested change
if (tr.changes.empty) return tr;
if (tr.changes.empty) {


ExplanationIt is recommended to always use braces and create explicit statement blocks.

Using the allowed syntax to just write a single statement can lead to very confusing
situations, especially where subsequently a developer might add another statement
while forgetting to add the braces (meaning that this wouldn't be included in the condition).

if (tr.newDoc.lines > 1 && !tr.isUserEvent('input.paste')) {
return [];
}

const removeNLs: ChangeSpec[] = [];
tr.changes.iterChanges((fromA, toA, fromB, toB, ins) => {
const lineIter = ins.iterLines().next();
if (ins.lines <= 1) return;
Copy link

Choose a reason for hiding this comment

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

suggestion (code-quality): Use block braces for ifs, whiles, etc. (use-braces)

Suggested change
if (ins.lines <= 1) return;
if (ins.lines <= 1) {


ExplanationIt is recommended to always use braces and create explicit statement blocks.

Using the allowed syntax to just write a single statement can lead to very confusing
situations, especially where subsequently a developer might add another statement
while forgetting to add the braces (meaning that this wouldn't be included in the condition).

// skip the first line
let len = fromB + lineIter.value.length;
lineIter.next();
// for the next lines, remove the leading NL
for (; !lineIter.done; lineIter.next()) {
removeNLs.push({ from: len, to: len + 1 });
len += lineIter.value.length + 1;
}
});

return [tr, { changes: removeNLs, sequential: true }];
});

return [
Expand Down
Loading