@@ -832,44 +832,62 @@ private void recomputeRange(final int startOffset, final int endOffset) throws B
832832 for (final TMToken t : tokens ) {
833833 final String prefNorm = t .grammarScope == null ? null : normalizeVariantScope (t .grammarScope );
834834 if (prefNorm != null && !Objects .equals (normalizeBaseScope (prefNorm ), baseRootNN )) {
835- if (firstEmbeddedStart < 0 )
835+ if (firstEmbeddedStart < 0 ) {
836836 firstEmbeddedStart = t .startIndex ;
837+ }
837838 lastEmbeddedStart = t .startIndex ;
838839 }
839840 }
840-
841- for ( final TMToken tok : tokens ) {
842- final String prefNorm = tok . grammarScope == null ? null : normalizeVariantScope ( tok . grammarScope );
843- final boolean isBase = prefNorm == null || Objects . equals ( normalizeBaseScope ( prefNorm ), baseRootNN );
844- final String root = isBase ? basePartitionType : scopeToPartitionType ( prefNorm != null ? prefNorm : baseRootNN );
845-
846- if ( currentType == null ) {
847- currentType = root ;
848- final boolean isEmbedded = ! isBase ;
849- final int firstTokenStart = lineOffset + tok . startIndex ;
850- currentStart = Math . max ( currentStart , isEmbedded ? lineOffset : firstTokenStart );
851- currentGrammarScopeStr = isBase ? baseRootNN : prefNorm ;
852- continue ;
841+ final boolean lineHasEmbedded = firstEmbeddedStart >= 0 ;
842+ boolean skipWhitespaceBaseLineInEmbeddedRun = false ;
843+ if (! lineHasEmbedded && currentType != null && ! currentType . equals ( basePartitionType )) {
844+ // Line has only base tokens but we are currently inside an embedded run.
845+ // If the text covered by this line within [startOffset,endOffset) is whitespace-only,
846+ // treat it as part of the embedded partition instead of starting a base segment.
847+ final int spanStart = Math . max ( lineOffset , startOffset );
848+ final int spanEnd = Math . min ( lineEnd , endOffset ) ;
849+ if ( spanEnd > spanStart ) {
850+ final String slice = doc . get ( spanStart , spanEnd - spanStart ) ;
851+ if ( slice . isBlank ()) {
852+ skipWhitespaceBaseLineInEmbeddedRun = true ;
853+ }
853854 }
855+ }
856+
857+ if (!skipWhitespaceBaseLineInEmbeddedRun ) {
858+ for (final TMToken tok : tokens ) {
859+ final String prefNorm = tok .grammarScope == null ? null : normalizeVariantScope (tok .grammarScope );
860+ final boolean isBase = prefNorm == null || Objects .equals (normalizeBaseScope (prefNorm ), baseRootNN );
861+ final String root = isBase ? basePartitionType : scopeToPartitionType (prefNorm != null ? prefNorm : baseRootNN );
862+
863+ if (currentType == null ) {
864+ currentType = root ;
865+ final boolean isEmbedded = !isBase ;
866+ final int firstTokenStart = lineOffset + tok .startIndex ;
867+ currentStart = Math .max (currentStart , isEmbedded ? lineOffset : firstTokenStart );
868+ currentGrammarScopeStr = isBase ? baseRootNN : prefNorm ;
869+ continue ;
870+ }
854871
855- if (!currentType .equals (root )) {
856- // While inside an embedded run, ignore base tokens that appear
857- // either at the start of the line (indentation) when another embedded token exists later,
858- // or anywhere before the last embedded token on this line (transient gaps between embedded tokens).
859- if (!currentType .equals (basePartitionType ) && basePartitionType .equals (root )) {
860- final boolean baseAtLineStartWithEmbedLater = tok .startIndex == 0 && firstEmbeddedStart > 0 ;
861- final boolean baseBeforeLastEmbedded = lastEmbeddedStart > 0 && tok .startIndex <= lastEmbeddedStart ;
862- if (baseAtLineStartWithEmbedLater || baseBeforeLastEmbedded ) {
863- // keep currentType and currentStart as-is
864- continue ;
872+ if (!currentType .equals (root )) {
873+ // While inside an embedded run, ignore base tokens that appear
874+ // either at the start of the line (indentation) when another embedded token exists later,
875+ // or anywhere before the last embedded token on this line (transient gaps between embedded tokens).
876+ if (!currentType .equals (basePartitionType ) && basePartitionType .equals (root )) {
877+ final boolean baseAtLineStartWithEmbedLater = tok .startIndex == 0 && firstEmbeddedStart > 0 ;
878+ final boolean baseBeforeLastEmbedded = lastEmbeddedStart > 0 && tok .startIndex <= lastEmbeddedStart ;
879+ if (baseAtLineStartWithEmbedLater || baseBeforeLastEmbedded ) {
880+ // keep currentType and currentStart as-is
881+ continue ;
882+ }
865883 }
884+ // Token type changed: finalize previous segment and start a new one
885+ final int segEnd = lineOffset + tok .startIndex ;
886+ addSeg (newSegs , currentStart , segEnd , currentType , currentGrammarScopeStr , baseScope );
887+ currentType = root ;
888+ currentStart = segEnd ;
889+ currentGrammarScopeStr = isBase ? baseRootNN : prefNorm ;
866890 }
867- // Token type changed: finalize previous segment and start a new one
868- final int segEnd = lineOffset + tok .startIndex ;
869- addSeg (newSegs , currentStart , segEnd , currentType , currentGrammarScopeStr , baseScope );
870- currentType = root ;
871- currentStart = segEnd ;
872- currentGrammarScopeStr = isBase ? baseRootNN : prefNorm ;
873891 }
874892 }
875893 }
0 commit comments