@@ -11,6 +11,7 @@ use harp::eval::RParseEvalOptions;
11
11
use harp:: exec:: RFunction ;
12
12
use harp:: exec:: RFunctionExt ;
13
13
use harp:: object:: RObject ;
14
+ use harp:: utils:: r_inherits;
14
15
use regex:: Regex ;
15
16
use tower_lsp:: lsp_types:: CompletionItem ;
16
17
use tree_sitter:: Node ;
@@ -170,6 +171,7 @@ fn call_prev_leaf_position_type(node: &Node, allow_ambiguous: bool) -> CallNodeP
170
171
pub ( super ) fn completions_from_evaluated_object_names (
171
172
name : & str ,
172
173
enquote : bool ,
174
+ node_type : NodeType ,
173
175
) -> Result < Option < Vec < CompletionItem > > > {
174
176
log:: info!( "completions_from_evaluated_object_names({name:?})" ) ;
175
177
@@ -204,6 +206,15 @@ pub(super) fn completions_from_evaluated_object_names(
204
206
let completions = if harp:: utils:: r_is_matrix ( object. sexp ) {
205
207
// Special case just for 2D arrays
206
208
completions_from_object_colnames ( object, name, enquote) ?
209
+ } else if r_inherits ( object. sexp , "data.table" ) {
210
+ // The `[` method for data.table uses NSE so we don't enquote the names
211
+ // https://github.com/posit-dev/positron/issues/3140
212
+ let enquote = match node_type {
213
+ NodeType :: Subset => false ,
214
+ NodeType :: Subset2 => true ,
215
+ _ => enquote,
216
+ } ;
217
+ completions_from_object_names ( object, name, enquote) ?
207
218
} else {
208
219
completions_from_object_names ( object, name, enquote) ?
209
220
} ;
@@ -259,6 +270,7 @@ mod tests {
259
270
use harp:: eval:: parse_eval_global;
260
271
use tree_sitter:: Point ;
261
272
273
+ use crate :: fixtures:: package_is_installed;
262
274
use crate :: lsp:: completions:: sources:: utils:: call_node_position_type;
263
275
use crate :: lsp:: completions:: sources:: utils:: completions_from_evaluated_object_names;
264
276
use crate :: lsp:: completions:: sources:: utils:: CallNodePositionType ;
@@ -426,7 +438,7 @@ mod tests {
426
438
parse_eval_global ( "x <- 1:2" ) . unwrap ( ) ;
427
439
parse_eval_global ( "names(x) <- c('a', 'b')" ) . unwrap ( ) ;
428
440
429
- let completions = completions_from_evaluated_object_names ( "x" , false )
441
+ let completions = completions_from_evaluated_object_names ( "x" , false , NodeType :: Subset )
430
442
. unwrap ( )
431
443
. unwrap ( ) ;
432
444
assert_eq ! ( completions. len( ) , 2 ) ;
@@ -438,7 +450,7 @@ mod tests {
438
450
// Data frame
439
451
parse_eval_global ( "x <- data.frame(a = 1, b = 2, c = 3)" ) . unwrap ( ) ;
440
452
441
- let completions = completions_from_evaluated_object_names ( "x" , false )
453
+ let completions = completions_from_evaluated_object_names ( "x" , false , NodeType :: Subset )
442
454
. unwrap ( )
443
455
. unwrap ( ) ;
444
456
assert_eq ! ( completions. len( ) , 3 ) ;
@@ -452,7 +464,7 @@ mod tests {
452
464
parse_eval_global ( "x <- array(1:2)" ) . unwrap ( ) ;
453
465
parse_eval_global ( "names(x) <- c('a', 'b')" ) . unwrap ( ) ;
454
466
455
- let completions = completions_from_evaluated_object_names ( "x" , false )
467
+ let completions = completions_from_evaluated_object_names ( "x" , false , NodeType :: Subset )
456
468
. unwrap ( )
457
469
. unwrap ( ) ;
458
470
assert_eq ! ( completions. len( ) , 2 ) ;
@@ -466,7 +478,7 @@ mod tests {
466
478
parse_eval_global ( "rownames(x) <- 'a'" ) . unwrap ( ) ;
467
479
parse_eval_global ( "colnames(x) <- 'b'" ) . unwrap ( ) ;
468
480
469
- let completions = completions_from_evaluated_object_names ( "x" , false )
481
+ let completions = completions_from_evaluated_object_names ( "x" , false , NodeType :: Subset )
470
482
. unwrap ( )
471
483
. unwrap ( ) ;
472
484
assert_eq ! ( completions. len( ) , 1 ) ;
@@ -482,12 +494,48 @@ mod tests {
482
494
parse_eval_global ( "rownames(x) <- 'a'" ) . unwrap ( ) ;
483
495
parse_eval_global ( "colnames(x) <- 'b'" ) . unwrap ( ) ;
484
496
485
- let completions = completions_from_evaluated_object_names ( "x" , false )
497
+ let completions = completions_from_evaluated_object_names ( "x" , false , NodeType :: Subset )
486
498
. unwrap ( )
487
499
. unwrap ( ) ;
488
500
assert ! ( completions. is_empty( ) ) ;
489
501
490
502
parse_eval_global ( "remove(x)" ) . unwrap ( ) ;
491
503
} )
492
504
}
505
+
506
+ #[ test]
507
+ fn test_data_table_completions ( ) {
508
+ r_task ( || {
509
+ // Skip test if data.table is not installed
510
+ if !package_is_installed ( "data.table" ) {
511
+ return ;
512
+ }
513
+
514
+ parse_eval_global ( "x <- data.table::as.data.table(mtcars)" ) . unwrap ( ) ;
515
+
516
+ // Subset completions
517
+ let completions = completions_from_evaluated_object_names ( "x" , false , NodeType :: Subset )
518
+ . unwrap ( )
519
+ . unwrap ( ) ;
520
+
521
+ assert_eq ! ( completions. len( ) , 11 ) ;
522
+ assert_eq ! ( completions. get( 0 ) . unwrap( ) . label, String :: from( "mpg" ) ) ;
523
+ assert_eq ! ( completions. get( 0 ) . unwrap( ) . insert_text, None ) ;
524
+
525
+ // Subset2 completions
526
+ let completions =
527
+ completions_from_evaluated_object_names ( "x" , false , NodeType :: Subset2 )
528
+ . unwrap ( )
529
+ . unwrap ( ) ;
530
+
531
+ assert_eq ! ( completions. len( ) , 11 ) ;
532
+ assert_eq ! ( completions. get( 0 ) . unwrap( ) . label, String :: from( "mpg" ) ) ;
533
+ assert_eq ! (
534
+ completions. get( 0 ) . unwrap( ) . insert_text,
535
+ Some ( "\" mpg\" " . to_string( ) )
536
+ ) ;
537
+
538
+ parse_eval_global ( "remove(x)" ) . unwrap ( ) ;
539
+ } )
540
+ }
493
541
}
0 commit comments