11use std:: { collections:: HashMap , sync:: OnceLock } ;
22
33use async_lsp:: lsp_types:: {
4- CodeAction , CodeActionKind , CodeActionOrCommand , CodeActionParams , TextEdit , WorkspaceEdit ,
4+ CodeAction , CodeActionKind , CodeActionOrCommand , CodeActionParams , Position , Range , TextEdit ,
5+ WorkspaceEdit ,
56} ;
67use convert_case:: { Case , Casing } ;
78use regex:: Regex ;
@@ -44,8 +45,9 @@ pub(super) fn case_actions(
4445 Some (
4546 CodeAction {
4647 title : item. to_string ( ) ,
47- kind : Some ( CodeActionKind :: REFACTOR_REWRITE ) ,
48+ kind : Some ( CodeActionKind :: REFACTOR_INLINE ) ,
4849 edit : Some ( WorkspaceEdit :: new ( changes) ) ,
50+ is_preferred : Some ( true ) ,
4951 ..Default :: default ( )
5052 }
5153 . into ( ) ,
@@ -63,74 +65,122 @@ fn md_table_line_rg() -> &'static Regex {
6365pub ( super ) fn markdown_actions (
6466 lang_id : String ,
6567 doc : & Rope ,
66- range_content : & String ,
6768 params : & CodeActionParams ,
6869) -> Vec < CodeActionOrCommand > {
6970 if lang_id != "markdown" {
7071 return Vec :: new ( ) ;
7172 }
7273
74+ let range_content = get_range_content ( doc, & params. range ) . unwrap_or ( "" . into ( ) ) ;
75+
7376 let mut items = Vec :: new ( ) ;
7477
7578 // 表格必须为三行以上,第二行起存在表头为 `- :|`
7679 if params. range . end . line - params. range . start . line > 1 {
77- let has_table = doc
78- . lines_at ( params . range . start . line as usize )
80+ let has_table = range_content
81+ . lines ( )
7982 . skip ( 1 )
8083 . any ( |line| md_table_line_rg ( ) . is_match ( line. to_string ( ) . trim ( ) ) ) ;
8184
8285 if has_table {
83- let out = markdown_table_formatter:: format_tables ( range_content) ;
84- items. push ( ( "Table Format" , out) ) ;
86+ let edits = vec ! [ TextEdit {
87+ range: params. range,
88+ new_text: markdown_table_formatter:: format_tables( range_content. to_string( ) ) ,
89+ } ] ;
90+
91+ items. push ( ( "Table Format" , edits) ) ;
8592 }
8693 }
8794
8895 if params. range . end . line != params. range . start . line {
89- let range_content = get_range_content ( doc, & params. range ) . unwrap_or ( "" . into ( ) ) ;
90-
9196 if !range_content. char ( 0 ) . is_numeric ( ) && range_content. char ( 1 ) != '.' {
92- let order_content : String = range_content
97+ let content = range_content
9398 . lines ( )
9499 . enumerate ( )
95- . map ( |( index , line) | {
96- let line = line . to_string ( ) ;
97- if ( params. range . end . line - params. range . start . line ) as usize == index
100+ . filter_map ( |( index_line , line) | {
101+ // 最后一行为空
102+ if ( params. range . end . line - params. range . start . line ) as usize == index_line
98103 && params. range . end . character == 0
99104 {
100- return line ;
105+ return None ;
101106 }
102- format ! ( "{}. {line}" , ( index + 1 ) )
107+
108+ let ( index_char, _) = line
109+ . chars ( )
110+ . enumerate ( )
111+ . find ( |( _index_char, c) | !c. is_ascii_whitespace ( ) )
112+ . unwrap_or_default ( ) ;
113+
114+ let line = index_line as u32 + params. range . start . line ;
115+ let character = index_char as u32 ;
116+
117+ Some ( TextEdit {
118+ range : Range :: new (
119+ Position :: new ( line, character) ,
120+ Position :: new ( line, character) ,
121+ ) ,
122+ new_text : format ! ( "{}. " , ( index_line + 1 ) ) ,
123+ } )
103124 } )
104125 . collect ( ) ;
105- items. push ( ( "Ordered List" , order_content) ) ;
126+
127+ items. push ( ( "Ordered List" , content) ) ;
106128 }
107129
108130 if range_content. char ( 0 ) != '-' && range_content. char ( 1 ) != ' ' {
109- let unorder_content: String = range_content
131+ let unorder_content = range_content
110132 . lines ( )
111133 . enumerate ( )
112- . map ( |( index, line) | {
113- let line = line. to_string ( ) ;
114- if ( params. range . end . line - params. range . start . line ) as usize == index
134+ . filter_map ( |( index_line, line) | {
135+ if ( params. range . end . line - params. range . start . line ) as usize == index_line
115136 && params. range . end . character == 0
116137 {
117- return line ;
138+ return None ;
118139 }
119- format ! ( "- {line}" )
140+
141+ let ( index_char, _) = line
142+ . chars ( )
143+ . enumerate ( )
144+ . find ( |( _index_char, c) | !c. is_ascii_whitespace ( ) ) ?;
145+
146+ let line = index_line as u32 + params. range . start . line ;
147+ let character = index_char as u32 ;
148+
149+ Some ( TextEdit {
150+ range : Range :: new (
151+ Position :: new ( line, character) ,
152+ Position :: new ( line, character) ,
153+ ) ,
154+ new_text : "- " . to_string ( ) ,
155+ } )
120156 } )
121157 . collect ( ) ;
122158
123- let task_content: String = range_content
159+ let task_content = range_content
124160 . lines ( )
125161 . enumerate ( )
126- . map ( |( index, line) | {
127- let line = line. to_string ( ) ;
128- if ( params. range . end . line - params. range . start . line ) as usize == index
162+ . filter_map ( |( index_line, line) | {
163+ if ( params. range . end . line - params. range . start . line ) as usize == index_line
129164 && params. range . end . character == 0
130165 {
131- return line ;
166+ return None ;
132167 }
133- format ! ( "- [ ] {line}" )
168+
169+ let ( index_char, _) = line
170+ . chars ( )
171+ . enumerate ( )
172+ . find ( |( _index_char, c) | !c. is_ascii_whitespace ( ) ) ?;
173+
174+ let line = index_line as u32 + params. range . start . line ;
175+ let character = index_char as u32 ;
176+
177+ Some ( TextEdit {
178+ range : Range :: new (
179+ Position :: new ( line, character) ,
180+ Position :: new ( line, character) ,
181+ ) ,
182+ new_text : "- [ ] " . to_string ( ) ,
183+ } )
134184 } )
135185 . collect ( ) ;
136186
@@ -141,20 +191,40 @@ pub(super) fn markdown_actions(
141191
142192 // 单行处理
143193 if params. range . start . line == params. range . end . line {
144- items. push ( ( "Bold" , format ! ( "**{range_content}**" ) ) ) ;
145- items. push ( ( "Italic" , format ! ( "_{range_content}_" ) ) ) ;
146- items. push ( ( "Strikethrough" , format ! ( "~~{range_content}~~" ) ) ) ;
194+ items. push ( (
195+ "Bold" ,
196+ vec ! [ TextEdit {
197+ range: params. range,
198+ new_text: format!( "**{range_content}**" ) ,
199+ } ] ,
200+ ) ) ;
201+ items. push ( (
202+ "Italic" ,
203+ vec ! [ TextEdit {
204+ range: params. range,
205+ new_text: format!( "_{range_content}_" ) ,
206+ } ] ,
207+ ) ) ;
208+ items. push ( (
209+ "Strikethrough" ,
210+ vec ! [ TextEdit {
211+ range: params. range,
212+ new_text: format!( "~~{range_content}~~" ) ,
213+ } ] ,
214+ ) ) ;
215+
216+ if params. range . start . character + 1 == params. range . end . character {
217+ // let line = doc.line(params.range.start.line as usize);
218+ // line.chars().find_map(f)
219+ // TODO TextEdit
220+ }
147221 }
148222
149223 items
150224 . iter ( )
151- . map ( |& ( item, ref out ) | {
225+ . map ( |( item, edits ) | {
152226 let mut changes = HashMap :: new ( ) ;
153- let edits = vec ! [ TextEdit {
154- range: params. range,
155- new_text: out. clone( ) ,
156- } ] ;
157- changes. insert ( params. text_document . uri . clone ( ) , edits) ;
227+ changes. insert ( params. text_document . uri . clone ( ) , edits. to_vec ( ) ) ;
158228
159229 CodeAction {
160230 title : item. to_string ( ) ,
0 commit comments