@@ -600,7 +600,7 @@ fn generate_completions(
600600) -> Result < Option < Vec < CompletionItem > > > {
601601 match context {
602602 CompletionContext :: DocumentRoot => {
603- let mut items = complete_date ( ) ?;
603+ let mut items = complete_date ( content , position ) ?;
604604 items. extend ( complete_directive_keywords ( ) ?) ;
605605 Ok ( Some ( items) )
606606 }
@@ -703,38 +703,54 @@ fn complete_directive_keywords() -> Result<Vec<CompletionItem>> {
703703}
704704
705705/// Complete date with current/previous/next month
706- fn complete_date ( ) -> Result < Vec < CompletionItem > > {
706+ fn complete_date ( content : & ropey :: Rope , position : Position ) -> Result < Vec < CompletionItem > > {
707707 let today = chrono:: Local :: now ( ) . naive_local ( ) . date ( ) ;
708708 let prev_month = sub_one_month ( today) . format ( "%Y-%m-" ) . to_string ( ) ;
709709 let cur_month = today. format ( "%Y-%m-" ) . to_string ( ) ;
710710 let next_month = add_one_month ( today) . format ( "%Y-%m-" ) . to_string ( ) ;
711711 let today_str = today. format ( "%Y-%m-%d" ) . to_string ( ) ;
712712
713+ // Calculate ranges for InsertReplaceEdit
714+ let line = content. line ( position. line as usize ) . to_string ( ) ;
715+ let ( insert_range, replace_range) = calculate_word_ranges ( & line, position) ;
716+
713717 Ok ( vec ! [
714- CompletionItem {
715- label: today_str,
716- detail: Some ( "today" . to_string( ) ) ,
717- kind: Some ( CompletionItemKind :: CONSTANT ) ,
718- ..Default :: default ( )
719- } ,
720- CompletionItem {
721- label: cur_month,
722- detail: Some ( "this month" . to_string( ) ) ,
723- kind: Some ( CompletionItemKind :: CONSTANT ) ,
724- ..Default :: default ( )
725- } ,
726- CompletionItem {
727- label: prev_month,
728- detail: Some ( "prev month" . to_string( ) ) ,
729- kind: Some ( CompletionItemKind :: CONSTANT ) ,
730- ..Default :: default ( )
731- } ,
732- CompletionItem {
733- label: next_month,
734- detail: Some ( "next month" . to_string( ) ) ,
735- kind: Some ( CompletionItemKind :: CONSTANT ) ,
736- ..Default :: default ( )
737- } ,
718+ create_completion_with_insert_replace(
719+ today_str,
720+ "today" . to_string( ) ,
721+ CompletionItemKind :: CONSTANT ,
722+ insert_range,
723+ replace_range,
724+ 1000.0 ,
725+ vec![ ] ,
726+ ) ,
727+ create_completion_with_insert_replace(
728+ cur_month,
729+ "this month" . to_string( ) ,
730+ CompletionItemKind :: CONSTANT ,
731+ insert_range,
732+ replace_range,
733+ 900.0 ,
734+ vec![ ] ,
735+ ) ,
736+ create_completion_with_insert_replace(
737+ prev_month,
738+ "prev month" . to_string( ) ,
739+ CompletionItemKind :: CONSTANT ,
740+ insert_range,
741+ replace_range,
742+ 800.0 ,
743+ vec![ ] ,
744+ ) ,
745+ create_completion_with_insert_replace(
746+ next_month,
747+ "next month" . to_string( ) ,
748+ CompletionItemKind :: CONSTANT ,
749+ insert_range,
750+ replace_range,
751+ 700.0 ,
752+ vec![ ] ,
753+ ) ,
738754 ] )
739755}
740756
@@ -1385,14 +1401,27 @@ mod tests {
13851401
13861402 #[ test]
13871403 fn test_complete_date ( ) {
1388- let items = complete_date ( ) . unwrap ( ) ;
1404+ let content = ropey:: Rope :: from_str ( "2026-01-" ) ;
1405+ let position = Position {
1406+ line : 0 ,
1407+ character : 8 ,
1408+ } ;
1409+ let items = complete_date ( & content, position) . unwrap ( ) ;
13891410 assert_eq ! ( items. len( ) , 4 ) ;
13901411
13911412 let details: Vec < String > = items. iter ( ) . filter_map ( |i| i. detail . clone ( ) ) . collect ( ) ;
13921413 assert ! ( details. contains( & "today" . to_string( ) ) ) ;
13931414 assert ! ( details. contains( & "this month" . to_string( ) ) ) ;
13941415 assert ! ( details. contains( & "prev month" . to_string( ) ) ) ;
13951416 assert ! ( details. contains( & "next month" . to_string( ) ) ) ;
1417+
1418+ // Verify that all items have text_edit set for proper replacement
1419+ for item in & items {
1420+ assert ! (
1421+ item. text_edit. is_some( ) ,
1422+ "Date completion should have text_edit"
1423+ ) ;
1424+ }
13961425 }
13971426
13981427 #[ test]
0 commit comments