@@ -1341,6 +1341,84 @@ void deltaWithLineInsertedInMiddle_shouldReturnOptimalDelta() {
13411341 assertThat (editSize ).isLessThan (originalDataSize );
13421342 }
13431343
1344+ @ Test
1345+ void deltaWithTextInsertedOnSameLine_shouldReturnOptimalDelta () {
1346+ // given - simulate inserting text on the same line without line breaks
1347+ // This tests the case raised by @nixel2007: text insertion without newline
1348+ String bsl1 = """
1349+ Перем А;
1350+ """ ;
1351+
1352+ String bsl2 = """
1353+ Перем Новая, А;
1354+ """ ;
1355+
1356+ DocumentContext context1 = TestUtils .getDocumentContext (bsl1 );
1357+ referenceIndexFiller .fill (context1 );
1358+ TextDocumentIdentifier textDocId1 = TestUtils .getTextDocumentIdentifier (context1 .getUri ());
1359+ SemanticTokens tokens1 = provider .getSemanticTokensFull (context1 , new SemanticTokensParams (textDocId1 ));
1360+
1361+ // Verify original tokens structure
1362+ var decoded1 = decode (tokens1 .getData ());
1363+ var expected1 = List .of (
1364+ new ExpectedToken (0 , 0 , 5 , SemanticTokenTypes .Keyword , "Перем" ),
1365+ new ExpectedToken (0 , 6 , 1 , SemanticTokenTypes .Variable , SemanticTokenModifiers .Definition , "А" ),
1366+ new ExpectedToken (0 , 7 , 1 , SemanticTokenTypes .Operator , ";" )
1367+ );
1368+ assertTokensMatch (decoded1 , expected1 );
1369+
1370+ DocumentContext context2 = TestUtils .getDocumentContext (context1 .getUri (), bsl2 );
1371+ referenceIndexFiller .fill (context2 );
1372+ SemanticTokens tokens2 = provider .getSemanticTokensFull (context2 , new SemanticTokensParams (textDocId1 ));
1373+
1374+ // Verify modified tokens structure
1375+ var decoded2 = decode (tokens2 .getData ());
1376+ var expected2 = List .of (
1377+ new ExpectedToken (0 , 0 , 5 , SemanticTokenTypes .Keyword , "Перем" ),
1378+ new ExpectedToken (0 , 6 , 5 , SemanticTokenTypes .Variable , SemanticTokenModifiers .Definition , "Новая" ),
1379+ new ExpectedToken (0 , 11 , 1 , SemanticTokenTypes .Operator , "," ),
1380+ new ExpectedToken (0 , 13 , 1 , SemanticTokenTypes .Variable , SemanticTokenModifiers .Definition , "А" ),
1381+ new ExpectedToken (0 , 14 , 1 , SemanticTokenTypes .Operator , ";" )
1382+ );
1383+ assertTokensMatch (decoded2 , expected2 );
1384+
1385+ // when
1386+ var deltaParams = new SemanticTokensDeltaParams (textDocId1 , tokens1 .getResultId ());
1387+ var result = provider .getSemanticTokensFullDelta (context2 , deltaParams );
1388+
1389+ // then - should return delta, not full tokens
1390+ assertThat (result .isRight ()).isTrue ();
1391+ var delta = result .getRight ();
1392+ assertThat (delta .getEdits ()).isNotEmpty ();
1393+ assertThat (delta .getEdits ()).hasSize (1 );
1394+
1395+ // Verify the delta edit details
1396+ // Original: [Перем, А, ;] - 3 tokens = 15 integers
1397+ // Modified: [Перем, Новая, ,, А, ;] - 5 tokens = 25 integers
1398+ //
1399+ // With lineOffset=0 inline edit handling:
1400+ // - Prefix match: "Перем" (1 token = 5 integers)
1401+ // - Suffix match: "А" and ";" (2 tokens = 10 integers)
1402+ // Note: "А" matches because the algorithm allows deltaStart to differ when lineOffset=0
1403+ // - Edit deletes: nothing (0 integers)
1404+ // - Edit inserts: "Новая" and "," (2 tokens = 10 integers)
1405+ var edit = delta .getEdits ().get (0 );
1406+ assertThat (edit .getStart ())
1407+ .as ("Edit should start after the prefix match (Перем = 5 integers)" )
1408+ .isEqualTo (5 );
1409+ assertThat (edit .getDeleteCount ())
1410+ .as ("Edit should delete nothing (suffix match includes А and ;)" )
1411+ .isEqualTo (0 );
1412+ assertThat (edit .getData ())
1413+ .as ("Edit should insert Новая and , tokens (2 tokens = 10 integers)" )
1414+ .isNotNull ()
1415+ .hasSize (10 );
1416+
1417+ // Verify the edit is optimal (smaller than sending all new tokens)
1418+ int editSize = edit .getDeleteCount () + edit .getData ().size ();
1419+ assertThat (editSize ).isLessThan (tokens2 .getData ().size ());
1420+ }
1421+
13441422 // endregion
13451423}
13461424
0 commit comments