@@ -138,6 +138,32 @@ def _do_skip_newlines(
138138 return j
139139
140140
141+ def _is_multiline_parameter (tokens : list [tokenize .TokenInfo ], index : int ) -> bool :
142+ """Determine if a token is a multiline string parameter.
143+
144+ A multiline string token spans multiple physical lines in the source code.
145+ This is determined by checking if the token's start and end line numbers
146+ are different.
147+
148+ Parameters
149+ ----------
150+ tokens : list[tokenize.TokenInfo]
151+ The list of tokens.
152+ index : int
153+ The index of the token to check.
154+
155+ Returns
156+ -------
157+ bool
158+ True if the token is a multiline string parameter, False otherwise.
159+ """
160+ if index >= len (tokens ):
161+ return False
162+
163+ token = tokens [index ]
164+ return token .type == tokenize .STRING and token .start [0 ] != token .end [0 ]
165+
166+
141167def _do_update_token_indices (
142168 tokens : list [tokenize .TokenInfo ],
143169) -> list [tokenize .TokenInfo ]:
@@ -166,9 +192,19 @@ def _do_update_token_indices(
166192 # If the current token line is the same as the preceding token line,
167193 # the starting row for the current token should be the same as the ending
168194 # line for the previous token unless both lines are NEWLINES.
169- if tokens [i ].line == tokens [i - 1 ].line and tokens [i - 1 ].type not in (
170- tokenize .NEWLINE ,
171- tokenize .NL ,
195+ # Also check if tokens are at the same position (handles multiline strings).
196+ is_multiline = _is_multiline_parameter (tokens , i - 1 )
197+ is_same_line = tokens [i ].line == tokens [i - 1 ].line
198+ is_same_position = tokens [i ].start [0 ] == tokens [i - 1 ].end [0 ]
199+
200+ if (
201+ is_multiline
202+ or (is_same_line or is_same_position )
203+ and tokens [i - 1 ].type
204+ not in (
205+ tokenize .NEWLINE ,
206+ tokenize .NL ,
207+ )
172208 ):
173209 _start_idx , _end_idx = _get_start_end_indices (
174210 tokens [i ],
@@ -461,7 +497,12 @@ def _get_start_end_indices(
461497 _end_row = _start_row
462498 _end_col = token .end [1 ]
463499
464- if num_rows > 1 and _end_row != prev_token .end [0 ]:
500+ # For multiline STRING tokens, update the end row but keep the original end column.
501+ # The num_cols calculation from the line is incorrect for multiline strings because
502+ # the line attribute contains more than just the string content.
503+ if num_rows > 1 and token .type == tokenize .STRING :
504+ _end_row = _start_row + num_rows - 1
505+ elif num_rows > 1 and _end_row != prev_token .end [0 ]:
465506 _end_row = _start_row + num_rows - 1
466507 _end_col = num_cols
467508
0 commit comments