Repository: microsoft/vscode (TypeScript)
Date: 2022-06-24 14:02:10+00:00
Task type: Bug Fix

Issue:
Word wrap algorithm behaves differently with bracket followed by comma
<!-- ⚠️⚠️ Do Not Delete This! bug_report_template ⚠️⚠️ -->
<!-- Please read our Rules of Conduct: https://opensource.microsoft.com/codeofconduct/ -->
<!-- 🕮 Read our guide about submitting issues: https://github.com/microsoft/vscode/wiki/Submitting-Bugs-and-Suggestions -->
<!-- 🔎 Search existing issues to avoid creating duplicates. -->
<!-- 🧪 Test using the latest Insiders build to see if your issue has already been fixed: https://code.visualstudio.com/insiders/ -->
<!-- 💡 Instead of creating your report here, use 'Report Issue' from the 'Help' menu in VS Code to pre-fill useful information. -->
<!-- 🔧 Launch with `code --disable-extensions` to check. -->
Does this issue occur when all extensions are disabled?: Yes

<!-- 🪓 If you answered No above, use 'Help: Start Extension Bisect' from Command Palette to try to identify the cause. -->
<!-- 📣 Issues caused by an extension need to be reported directly to the extension publisher. The 'Help > Report Issue' dialog can assist with this. -->
- VS Code Version: 1.68.1 (Universal)
- OS Version: macOS 10.14.6

Steps to Reproduce:

1. Create a file with the following content (the two lines differ only in that brackets are replaced with s):
   ```
   this is a line of (text), text that sits on a line
   this is a line of stexts, text that sits on a line
   ```

2. Use the following settings:
   ```
   "editor.wordWrapColumn": 24,
   "editor.rulers": [24],
   "editor.wordWrap": "wordWrapColumn",
   "editor.renderWhitespace": "all",
   ```

3. Observe that only the comma is wrapped to the next line in the first instance, but the entire word is wrapped with the comma (`stexts,`) in the second instance.
![vsc_wrapping](https://user-images.githubusercontent.com/5632994/174866165-2a8697df-088e-41b1-b7d5-27eb86115bc6.png)

This is a reopening of the original issue expressed in #33366 -- in that thread, a related issue was expressed and fixed, but the issue described above remains.



Issue discussion:
Thanks for creating this issue! It looks like you may be using an old version of VS Code, the latest stable release is 1.68.1. Please try upgrading to the latest version and checking whether this issue remains.

Happy Coding!
Updated per the bot's suggestion, issue remains.

Solution patch:
diff --git a/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts b/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts
--- a/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts
+++ b/src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts
@@ -411,7 +411,7 @@ function createLineBreaks(classifier: WrappingCharacterClassifier, _lineText: st
 	for (let i = startOffset; i < len; i++) {
 		const charStartOffset = i;
 		const charCode = lineText.charCodeAt(i);
-		let charCodeClass: number;
+		let charCodeClass: CharacterClass;
 		let charWidth: number;
 
 		if (strings.isHighSurrogate(charCode)) {
@@ -489,9 +489,9 @@ function canBreak(prevCharCode: number, prevCharCodeClass: CharacterClass, charC
 	return (
 		charCode !== CharCode.Space
 		&& (
-			(prevCharCodeClass === CharacterClass.BREAK_AFTER)
+			(prevCharCodeClass === CharacterClass.BREAK_AFTER && charCodeClass !== CharacterClass.BREAK_AFTER) // break at the end of multiple BREAK_AFTER
+			|| (prevCharCodeClass !== CharacterClass.BREAK_BEFORE && charCodeClass === CharacterClass.BREAK_BEFORE) // break at the start of multiple BREAK_BEFORE
 			|| (prevCharCodeClass === CharacterClass.BREAK_IDEOGRAPHIC && charCodeClass !== CharacterClass.BREAK_AFTER)
-			|| (charCodeClass === CharacterClass.BREAK_BEFORE)
 			|| (charCodeClass === CharacterClass.BREAK_IDEOGRAPHIC && prevCharCodeClass !== CharacterClass.BREAK_BEFORE)
 		)
 	);


Test patch:
diff --git a/src/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts b/src/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts
--- a/src/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts
+++ b/src/vs/editor/test/common/viewModel/monospaceLineBreaksComputer.test.ts
@@ -116,9 +116,9 @@ suite('Editor ViewModel - MonospaceLineBreaksComputer', () => {
 		assertLineBreaks(factory, 4, 5, 'aaa))|).aaa');
 		assertLineBreaks(factory, 4, 5, 'aaa))|).|aaaa');
 		assertLineBreaks(factory, 4, 5, 'aaa)|().|aaa');
-		assertLineBreaks(factory, 4, 5, 'aaa(|().|aaa');
-		assertLineBreaks(factory, 4, 5, 'aa.(|().|aaa');
-		assertLineBreaks(factory, 4, 5, 'aa.(.|).aaa');
+		assertLineBreaks(factory, 4, 5, 'aaa|(().|aaa');
+		assertLineBreaks(factory, 4, 5, 'aa.|(().|aaa');
+		assertLineBreaks(factory, 4, 5, 'aa.|(.).|aaa');
 	});
 
 	function assertLineBreakDataEqual(a: ModelLineProjectionData | null, b: ModelLineProjectionData | null): void {
@@ -293,6 +293,11 @@ suite('Editor ViewModel - MonospaceLineBreaksComputer', () => {
 		assertLineBreaks(factory, 4, 23, 'this is a line of |text, text that sits |on a line', WrappingIndent.Same);
 	});
 
+	test('issue #152773: Word wrap algorithm behaves differently with bracket followed by comma', () => {
+		const factory = new MonospaceLineBreaksComputerFactory(EditorOptions.wordWrapBreakBeforeCharacters.defaultValue, EditorOptions.wordWrapBreakAfterCharacters.defaultValue);
+		assertLineBreaks(factory, 4, 24, 'this is a line of |(text), text that sits |on a line', WrappingIndent.Same);
+	});
+
 	test('issue #112382: Word wrap doesn\'t work well with control characters', () => {
 		const factory = new MonospaceLineBreaksComputerFactory(EditorOptions.wordWrapBreakBeforeCharacters.defaultValue, EditorOptions.wordWrapBreakAfterCharacters.defaultValue);
 		assertLineBreaks(factory, 4, 6, '\x06\x06\x06|\x06\x06\x06', WrappingIndent.Same);