@@ -1155,6 +1155,11 @@ fn goto_file_vsplit(cx: &mut Context) {
1155
1155
1156
1156
/// Goto files in selection.
1157
1157
fn goto_file_impl ( cx : & mut Context , action : Action ) {
1158
+ struct OpenOption {
1159
+ path : PathBuf ,
1160
+ location : Option < ( usize , usize ) > ,
1161
+ }
1162
+
1158
1163
let ( view, doc) = current_ref ! ( cx. editor) ;
1159
1164
let text = doc. text ( ) ;
1160
1165
let selections = doc. selection ( view. id ) ;
@@ -1189,15 +1194,83 @@ fn goto_file_impl(cx: &mut Context, action: Action) {
1189
1194
. to_string ( ) ,
1190
1195
) ;
1191
1196
}
1197
+
1198
+ // Most compilers/linters print in this format
1199
+ static REGEX_FILE_ROW_COL : Lazy < Regex > =
1200
+ Lazy :: new ( || Regex :: new ( "^(?P<path>.[^:]+):(?P<row>\\ d+)(:(?P<col>\\ d+))?$" ) . unwrap ( ) ) ;
1201
+
1192
1202
for sel in paths {
1193
1203
let p = sel. trim ( ) ;
1194
1204
if !p. is_empty ( ) {
1195
1205
let path = & rel_path. join ( p) ;
1196
1206
if path. is_dir ( ) {
1197
1207
let picker = ui:: file_picker ( path. into ( ) , & cx. editor . config ( ) ) ;
1198
1208
cx. push_layer ( Box :: new ( overlaid ( picker) ) ) ;
1199
- } else if let Err ( e) = cx. editor . open ( path, action) {
1200
- cx. editor . set_error ( format ! ( "Open file failed: {:?}" , e) ) ;
1209
+ } else {
1210
+ let open_option = match REGEX_FILE_ROW_COL . captures ( p) {
1211
+ Some ( file_row_col) => {
1212
+ let path = file_row_col. name ( "path" ) . unwrap ( ) . as_str ( ) ;
1213
+ let loc = match file_row_col
1214
+ . name ( "row" )
1215
+ . unwrap ( )
1216
+ . as_str ( )
1217
+ . parse :: < NonZeroUsize > ( )
1218
+ {
1219
+ Ok ( row) => match file_row_col. name ( "col" ) {
1220
+ Some ( col) => match col. as_str ( ) . parse :: < NonZeroUsize > ( ) {
1221
+ Ok ( col) => Some ( ( row. get ( ) , col. get ( ) ) ) ,
1222
+ Err ( _) => None ,
1223
+ } ,
1224
+ None => Some ( ( row. get ( ) , 1 ) ) ,
1225
+ } ,
1226
+ Err ( _) => None ,
1227
+ } ;
1228
+
1229
+ OpenOption {
1230
+ path : PathBuf :: from ( path) ,
1231
+ location : loc,
1232
+ }
1233
+ }
1234
+ None => OpenOption {
1235
+ path : PathBuf :: from ( p) ,
1236
+ location : None ,
1237
+ } ,
1238
+ } ;
1239
+
1240
+ match cx. editor . open ( & open_option. path , action) {
1241
+ Ok ( _) => {
1242
+ if let Some ( ( row, col) ) = open_option. location {
1243
+ let ( view, doc) = current ! ( cx. editor) ;
1244
+
1245
+ let doc_text = doc. text ( ) ;
1246
+
1247
+ // Number of lines is always positive even for empty buffers
1248
+ let doc_lines = doc_text. len_lines ( ) ;
1249
+
1250
+ // Zero-based line index
1251
+ let ind_adjusted_line = usize:: min ( row, doc_lines) - 1 ;
1252
+
1253
+ let ind_dest = if row > doc_lines {
1254
+ // Discard designated col and simply set to end of doc
1255
+ doc_text. len_chars ( ) . saturating_sub ( 1 )
1256
+ } else {
1257
+ let line_len = doc_text. line ( ind_adjusted_line) . len_chars ( ) ;
1258
+
1259
+ let adjusted_ind_col = if line_len == 0 {
1260
+ 0
1261
+ } else {
1262
+ usize:: min ( col, line_len) - 1
1263
+ } ;
1264
+
1265
+ doc_text. line_to_char ( ind_adjusted_line) + adjusted_ind_col
1266
+ } ;
1267
+
1268
+ doc. set_selection ( view. id , Selection :: point ( ind_dest) ) ;
1269
+ align_view ( doc, view, Align :: Center ) ;
1270
+ }
1271
+ }
1272
+ Err ( e) => cx. editor . set_error ( format ! ( "Open file failed: {:?}" , e) ) ,
1273
+ }
1201
1274
}
1202
1275
}
1203
1276
}
0 commit comments