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