@@ -3706,6 +3706,18 @@ fn open(cx: &mut Context, open: Open, comment_continuation: CommentContinuation)
37063706 let continue_comment_token = continue_comment_tokens
37073707 . and_then ( |tokens| comment:: get_comment_token ( text, tokens, curr_line_num) ) ;
37083708
3709+ // Check if this is an empty comment line (just the token with optional whitespace).
3710+ // If so, we clear the comment token instead of continuing it.
3711+ let is_empty_comment = continue_comment_token
3712+ . is_some_and ( |token| comment:: is_empty_comment_line ( text, token, curr_line_num) ) ;
3713+
3714+ // If empty comment, don't continue the comment
3715+ let continue_comment_token = if is_empty_comment {
3716+ None
3717+ } else {
3718+ continue_comment_token
3719+ } ;
3720+
37093721 // Index to insert newlines after, as well as the char width
37103722 // to use to compensate for those inserted newlines.
37113723 let ( above_next_line_end_index, above_next_line_end_width) = if next_new_line_num == 0 {
@@ -3755,30 +3767,95 @@ fn open(cx: &mut Context, open: Open, comment_continuation: CommentContinuation)
37553767
37563768 let text = text. repeat ( count) ;
37573769
3758- // calculate new selection ranges
3759- let pos = offs + above_next_line_end_index + above_next_line_end_width;
3760- let comment_len = continue_comment_token
3761- . map ( |token| token. len ( ) + 1 ) // `+ 1` for the extra space added
3762- . unwrap_or_default ( ) ;
3763- for i in 0 ..count {
3764- // pos -> beginning of reference line,
3765- // + (i * (line_ending_len + indent_len + comment_len)) -> beginning of i'th line from pos (possibly including comment token)
3766- // + indent_len + comment_len -> -> indent for i'th line
3767- ranges. push ( Range :: point (
3768- pos + ( i * ( doc. line_ending . len_chars ( ) + indent_len + comment_len) )
3769- + indent_len
3770- + comment_len,
3771- ) ) ;
3772- }
3770+ // calculate new selection ranges and return the change
3771+ if is_empty_comment {
3772+ // For empty comment lines, delete the token from the current line
3773+ // and insert just the newline with indentation
3774+ let curr_line_start = contents. line_to_char ( curr_line_num) ;
3775+ let indent_end_pos = curr_line_start + line. first_non_whitespace_char ( ) . unwrap_or ( 0 ) ;
3776+ let curr_line_end = line_end_char_index ( & contents. slice ( ..) , curr_line_num) ;
3777+
3778+ if open == Open :: Above {
3779+ // For O (open above), we need to insert a new line above while clearing
3780+ // the token from the current line. We expand the replacement range to
3781+ // include the end of the previous line (or start of file).
3782+ let ( replace_from, replacement_text) = if curr_line_num == 0 {
3783+ // First line: replace from start of file
3784+ // Replace " - " with " \n " (indent + newline + indent)
3785+ let mut replacement = String :: with_capacity ( indent_len * 2 + doc. line_ending . len_chars ( ) ) ;
3786+ replacement. push_str ( & indent) ;
3787+ replacement. push_str ( doc. line_ending . as_str ( ) ) ;
3788+ replacement. push_str ( & indent) ;
3789+ ( 0 , replacement)
3790+ } else {
3791+ // Not first line: replace from end of previous line
3792+ // Replace "\n - " with "\n \n " (newline + indent + newline + indent)
3793+ let mut replacement = String :: with_capacity ( indent_len * 2 + doc. line_ending . len_chars ( ) * 2 ) ;
3794+ replacement. push_str ( doc. line_ending . as_str ( ) ) ;
3795+ replacement. push_str ( & indent) ;
3796+ replacement. push_str ( doc. line_ending . as_str ( ) ) ;
3797+ replacement. push_str ( & indent) ;
3798+ ( above_next_line_end_index, replacement)
3799+ } ;
37733800
3774- // update the offset for the next range
3775- offs += text . chars ( ) . count ( ) ;
3801+ let replacement_text = replacement_text . repeat ( count ) ;
3802+ let chars_deleted = curr_line_end - replace_from ;
37763803
3777- (
3778- above_next_line_end_index,
3779- above_next_line_end_index,
3780- Some ( text. into ( ) ) ,
3781- )
3804+ // Cursor should be on the new line (which is above the cleared line)
3805+ for i in 0 ..count {
3806+ let cursor_pos = if curr_line_num == 0 {
3807+ // On first line, cursor at end of first indent
3808+ offs + indent_len + i * ( doc. line_ending . len_chars ( ) + indent_len)
3809+ } else {
3810+ // Not first line, cursor after first newline + indent
3811+ offs + replace_from + doc. line_ending . len_chars ( ) + indent_len
3812+ + i * ( doc. line_ending . len_chars ( ) + indent_len)
3813+ } ;
3814+ ranges. push ( Range :: point ( cursor_pos) ) ;
3815+ }
3816+
3817+ offs += replacement_text. chars ( ) . count ( ) - chars_deleted;
3818+ ( replace_from, curr_line_end, Some ( replacement_text. into ( ) ) )
3819+ } else {
3820+ // For o (open below), replace the token with newline + indent
3821+ let chars_deleted = curr_line_end - indent_end_pos;
3822+
3823+ // Calculate cursor position on the new line
3824+ for i in 0 ..count {
3825+ ranges. push ( Range :: point (
3826+ offs + indent_end_pos
3827+ + ( i + 1 ) * ( doc. line_ending . len_chars ( ) + indent_len) ,
3828+ ) ) ;
3829+ }
3830+
3831+ offs += text. chars ( ) . count ( ) - chars_deleted;
3832+ ( indent_end_pos, curr_line_end, Some ( text. into ( ) ) )
3833+ }
3834+ } else {
3835+ let pos = offs + above_next_line_end_index + above_next_line_end_width;
3836+ let comment_len = continue_comment_token
3837+ . map ( |token| token. len ( ) + 1 ) // `+ 1` for the extra space added
3838+ . unwrap_or_default ( ) ;
3839+ for i in 0 ..count {
3840+ // pos -> beginning of reference line,
3841+ // + (i * (line_ending_len + indent_len + comment_len)) -> beginning of i'th line from pos (possibly including comment token)
3842+ // + indent_len + comment_len -> -> indent for i'th line
3843+ ranges. push ( Range :: point (
3844+ pos + ( i * ( doc. line_ending . len_chars ( ) + indent_len + comment_len) )
3845+ + indent_len
3846+ + comment_len,
3847+ ) ) ;
3848+ }
3849+
3850+ // update the offset for the next range
3851+ offs += text. chars ( ) . count ( ) ;
3852+
3853+ (
3854+ above_next_line_end_index,
3855+ above_next_line_end_index,
3856+ Some ( text. into ( ) ) ,
3857+ )
3858+ }
37823859 } ) ;
37833860
37843861 transaction = transaction. with_selection ( Selection :: new ( ranges, selection. primary_index ( ) ) ) ;
@@ -4321,7 +4398,31 @@ pub mod insert {
43214398 let continue_comment_token = continue_comment_tokens
43224399 . and_then ( |tokens| comment:: get_comment_token ( text, tokens, current_line) ) ;
43234400
4324- let ( from, to, local_offs) = if let Some ( idx) =
4401+ // Check if this is an empty comment line (just the token with optional whitespace).
4402+ // If so, we clear the comment token instead of continuing it.
4403+ let is_empty_comment = continue_comment_token
4404+ . is_some_and ( |token| comment:: is_empty_comment_line ( text, token, current_line) ) ;
4405+
4406+ let ( from, to, local_offs) = if is_empty_comment {
4407+ // Clear the empty comment token and insert a plain newline with just indentation
4408+ let line = text. line ( current_line) ;
4409+ let indent_end = line. first_non_whitespace_char ( ) . unwrap_or ( 0 ) ;
4410+ let indent = line. slice ( ..indent_end) . to_string ( ) ;
4411+
4412+ new_text. reserve_exact ( line_ending. len ( ) + indent. len ( ) ) ;
4413+ new_text. push_str ( line_ending) ;
4414+ new_text. push_str ( & indent) ;
4415+
4416+ let delete_from = line_start + indent_end;
4417+ chars_deleted = pos - delete_from;
4418+ last_pos = pos;
4419+
4420+ (
4421+ delete_from,
4422+ pos,
4423+ new_text. chars ( ) . count ( ) as isize - chars_deleted as isize ,
4424+ )
4425+ } else if let Some ( idx) =
43254426 text. slice ( line_start..pos) . last_non_whitespace_char ( )
43264427 {
43274428 let first_trailing_whitespace_char = ( line_start + idx + 1 ) . clamp ( last_pos, pos) ;
0 commit comments