Skip to content

Commit 2b4acfe

Browse files
authored
Merge pull request #9 from Fred-Wu/Version-3.0.5
Version 3.0.5 ### Major * Added a UI button to refresh data viewer. ### Minor * Simplified data viewer loading overlay text. * Fixed completion trigger `$` that may not show anything, ie from R6 or R7. For a package like `torch`, if a method was not implemented, and resulted in an error, the completion would not suggest the method. * Fixed data viewer if an object is an environment.
2 parents 5ebde5b + 897adff commit 2b4acfe

7 files changed

Lines changed: 245 additions & 42 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## 3.0.5 - 2026-01-04
4+
5+
### Major
6+
* Added a UI button to refresh data viewer.
7+
8+
### Minor
9+
* Simplified data viewer loading overlay text.
10+
* Fixed completion trigger `$` that may not show anything, ie from R6 or R7. For a package like `torch`, if a method was not implemented, and resulted in an error, the completion would not suggest the method.
11+
* Fixed data viewer if an object is an environment.
12+
13+
14+
315
## 3.0.2 - 2025-11-17
416

517
### Minor

R/session/vsc.R

Lines changed: 136 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ dataview_table <- local({
116116
sortModel = NULL, filterModel = NULL,
117117
metadata_only = FALSE, force = FALSE) {
118118

119-
if (!is.data.frame(data) && !is.matrix(data) && !inherits(data, "ArrowTabular")) {
119+
if (!is.data.frame(data) && !is.matrix(data) &&
120+
!inherits(data, "ArrowTabular") &&
121+
!inherits(data, "polars_data_frame")) {
120122
stop("data must be a data frame, a matrix or an arrow table object.")
121123
}
122124

@@ -322,13 +324,21 @@ if (use_webserver) {
322324
}
323325

324326
result <- lapply(names, function(name) {
325-
item <- obj[[name]]
327+
err_msg <- NULL
328+
item <- tryCatch(obj[[name]], error = function(e) {
329+
err_msg <<- conditionMessage(e)
330+
NULL
331+
})
332+
if (!is.null(err_msg)) {
333+
return(NULL)
334+
}
326335
list(
327336
name = name,
328337
type = typeof(item),
329338
str = try_capture_str(item)
330339
)
331340
})
341+
result <- Filter(Negate(is.null), result)
332342
return(result)
333343
}
334344

@@ -352,10 +362,19 @@ if (use_webserver) {
352362
}
353363
fm_env <- get(".dataview_first_map", envir = .GlobalEnv)
354364

355-
obj <- if (exists(varname, envir = .GlobalEnv)) {
356-
get(varname, envir = .GlobalEnv)
357-
} else {
358-
eval(parse(text = varname), envir = .GlobalEnv)
365+
obj <- NULL
366+
if (exists(".vsc_env_view_cache", envir = .GlobalEnv, inherits = FALSE)) {
367+
cache_env <- get(".vsc_env_view_cache", envir = .GlobalEnv)
368+
if (!is.null(cache_env[[varname]])) {
369+
obj <- cache_env[[varname]]
370+
}
371+
}
372+
if (is.null(obj)) {
373+
obj <- if (exists(varname, envir = .GlobalEnv)) {
374+
get(varname, envir = .GlobalEnv)
375+
} else {
376+
eval(parse(text = varname), envir = .GlobalEnv)
377+
}
359378
}
360379

361380
attr(obj, "_dvkey") <- varname
@@ -366,6 +385,104 @@ if (use_webserver) {
366385
out <- dataview_table(obj, start, end, sortModel, filterModel, force = is_first)
367386
out$columns <- NULL
368387
return(out)
388+
},
389+
dataview_refresh = function(varname, ...) {
390+
if (!exists(".dataview_first_map", envir = .GlobalEnv, inherits = FALSE)) {
391+
assign(".dataview_first_map", new.env(parent = emptyenv()), envir = .GlobalEnv)
392+
}
393+
fm_env <- get(".dataview_first_map", envir = .GlobalEnv)
394+
fm_env[[varname]] <- NULL
395+
if (exists(".vsc_env_view_cache", envir = .GlobalEnv, inherits = FALSE)) {
396+
cache_env <- get(".vsc_env_view_cache", envir = .GlobalEnv)
397+
cache_env[[varname]] <- NULL
398+
}
399+
400+
obj <- if (exists(varname, envir = .GlobalEnv)) {
401+
get(varname, envir = .GlobalEnv)
402+
} else {
403+
eval(parse(text = varname), envir = .GlobalEnv)
404+
}
405+
406+
if (is.environment(obj)) {
407+
all_names <- ls(obj)
408+
is_active <- vapply(all_names, bindingIsActive, logical(1), USE.NAMES = TRUE, obj)
409+
is_promise <- rlang::env_binding_are_lazy(obj, all_names[!is_active])
410+
obj <- lapply(all_names, function(name) {
411+
if (isTRUE(is_promise[name])) {
412+
data.frame(
413+
name = name,
414+
class = "promise",
415+
type = "promise",
416+
length = 0L,
417+
size = 0L,
418+
value = "(promise)",
419+
stringsAsFactors = FALSE,
420+
check.names = FALSE
421+
)
422+
} else if (isTRUE(is_active[name])) {
423+
data.frame(
424+
name = name,
425+
class = "active_binding",
426+
type = "active_binding",
427+
length = 0L,
428+
size = 0L,
429+
value = "(active-binding)",
430+
stringsAsFactors = FALSE,
431+
check.names = FALSE
432+
)
433+
} else {
434+
obj_item <- obj[[name]]
435+
data.frame(
436+
name = name,
437+
class = paste0(class(obj_item), collapse = ", "),
438+
type = typeof(obj_item),
439+
length = length(obj_item),
440+
size = as.integer(object.size(obj_item)),
441+
value = trimws(try_capture_str(obj_item, 0)),
442+
stringsAsFactors = FALSE,
443+
check.names = FALSE
444+
)
445+
}
446+
})
447+
names(obj) <- all_names
448+
if (length(obj)) {
449+
obj <- do.call(rbind, obj)
450+
} else {
451+
obj <- data.frame(
452+
name = character(),
453+
class = character(),
454+
type = character(),
455+
length = integer(),
456+
size = integer(),
457+
value = character(),
458+
stringsAsFactors = FALSE,
459+
check.names = FALSE
460+
)
461+
}
462+
if (!exists(".vsc_env_view_cache", envir = .GlobalEnv, inherits = FALSE)) {
463+
assign(".vsc_env_view_cache", new.env(parent = emptyenv()), envir = .GlobalEnv)
464+
}
465+
cache_env <- get(".vsc_env_view_cache", envir = .GlobalEnv)
466+
cache_env[[varname]] <- obj
467+
}
468+
469+
if (inherits(obj, "ArrowTabular")) {
470+
obj <- obj[1, ]$to_data_frame()
471+
}
472+
473+
if (inherits(obj, "polars_data_frame")) {
474+
obj <- as.data.frame(obj[0, ])
475+
}
476+
477+
if (!is.data.frame(obj) && !is.matrix(obj)) {
478+
stop("dataview_refresh expects a data.frame or matrix.")
479+
}
480+
481+
attr(obj, "_dvkey") <- varname
482+
meta <- dataview_table(obj, start = 0, end = 0, force = TRUE)
483+
file <- tempfile(tmpdir = tempdir, fileext = ".json")
484+
jsonlite::write_json(meta, file, na = "string", null = "null", auto_unbox = TRUE, force = TRUE)
485+
list(file = file)
369486
}
370487
)
371488

@@ -727,13 +844,18 @@ if (show_view) {
727844
x <- x[1, ]$to_data_frame()
728845
}
729846

847+
if (inherits(x, "polars_data_frame")) {
848+
x <- as.data.frame(x[0, ])
849+
}
850+
730851
if (is.environment(x)) {
731852
all_names <- ls(x)
732853
is_active <- vapply(all_names, bindingIsActive, logical(1), USE.NAMES = TRUE, x)
733854
is_promise <- rlang::env_binding_are_lazy(x, all_names[!is_active])
734855
x <- lapply(all_names, function(name) {
735856
if (isTRUE(is_promise[name])) {
736857
data.frame(
858+
name = name,
737859
class = "promise",
738860
type = "promise",
739861
length = 0L,
@@ -744,6 +866,7 @@ if (show_view) {
744866
)
745867
} else if (isTRUE(is_active[name])) {
746868
data.frame(
869+
name = name,
747870
class = "active_binding",
748871
type = "active_binding",
749872
length = 0L,
@@ -755,6 +878,7 @@ if (show_view) {
755878
} else {
756879
obj <- x[[name]]
757880
data.frame(
881+
name = name,
758882
class = paste0(class(obj), collapse = ", "),
759883
type = typeof(obj),
760884
length = length(obj),
@@ -770,6 +894,7 @@ if (show_view) {
770894
x <- do.call(rbind, x)
771895
} else {
772896
x <- data.frame(
897+
name = character(),
773898
class = character(),
774899
type = character(),
775900
length = integer(),
@@ -779,6 +904,11 @@ if (show_view) {
779904
check.names = FALSE
780905
)
781906
}
907+
if (!exists(".vsc_env_view_cache", envir = .GlobalEnv, inherits = FALSE)) {
908+
assign(".vsc_env_view_cache", new.env(parent = emptyenv()), envir = .GlobalEnv)
909+
}
910+
cache_env <- get(".vsc_env_view_cache", envir = .GlobalEnv)
911+
cache_env[[title]] <- x
782912
}
783913
if (is.data.frame(x) || is.matrix(x)) {
784914
x <- data.table::as.data.table(x[0, , drop = FALSE])

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "r",
33
"displayName": "R",
44
"description": "R Extension for Visual Studio Code",
5-
"version": "3.0.4",
5+
"version": "3.0.5",
66
"author": "REditorSupport",
77
"license": "SEE LICENSE IN LICENSE",
88
"publisher": "REditorSupport",
@@ -250,6 +250,12 @@
250250
"icon": "$(link-external)",
251251
"category": "R"
252252
},
253+
{
254+
"command": "r.dataview.refresh",
255+
"title": "Refresh Data Viewer",
256+
"icon": "$(refresh)",
257+
"category": "R Data Viewer"
258+
},
253259
{
254260
"command": "r.showHelp",
255261
"title": "Show help",
@@ -1025,6 +1031,11 @@
10251031
"when": "resourceScheme =~ /webview/ && r.browser.active",
10261032
"group": "navigation"
10271033
},
1034+
{
1035+
"command": "r.dataview.refresh",
1036+
"when": "resourceScheme =~ /webview/ && r.dataview.active",
1037+
"group": "navigation"
1038+
},
10281039
{
10291040
"command": "editor.action.webvieweditor.showFind",
10301041
"when": "resourceScheme =~ /webview/ && r.browser.active",

src/completions.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import { cleanLine } from './lineCache';
1313
import { globalRHelp } from './extension';
1414
import { config } from './util';
1515
import { getChunks } from './rmarkdown';
16-
import { CompletionItemKind } from 'vscode-languageclient';
1716

1817

1918
// Get with names(roxygen2:::default_tags())
@@ -222,10 +221,18 @@ function getCompletionItemsFromElements(elements: RObjectElement[], detail: stri
222221
const len = elements.length.toString().length;
223222
let index = 0;
224223
return elements.map((e) => {
225-
const item = new vscode.CompletionItem(e.name, (e.type === 'closure' || e.type === 'builtin') ? CompletionItemKind.Function : vscode.CompletionItemKind.Variable);
224+
const isFunctionType = e.type === 'closure' || e.type === 'builtin';
225+
const isFunctionStr = /^\s*function\s*\(/.test(e.str);
226+
const item = new vscode.CompletionItem(
227+
e.name,
228+
isFunctionType ? vscode.CompletionItemKind.Function : vscode.CompletionItemKind.Variable
229+
);
226230
item.detail = detail;
227231
item.documentation = new vscode.MarkdownString(`\`\`\`r\n${e.str}\n\`\`\``);
228232
item.sortText = `0-${index.toString().padStart(len, '0')}`;
233+
if (isFunctionType || isFunctionStr) {
234+
item.insertText = new vscode.SnippetString(`${e.name}($0)`);
235+
}
229236
index++;
230237
return item;
231238
});

src/extension.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<apiImp
5252
// assign extension context to global variable
5353
extensionContext = context;
5454

55-
// hide R activity icon until a session attaches
55+
// hide R activity icon until a session attaches
5656
void vscode.commands.executeCommand('setContext', 'rSessionActive', false);
5757

5858
// assign session watcher setting to global variable
@@ -150,6 +150,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<apiImp
150150
// browser controls
151151
'r.browser.refresh': session.refreshBrowser,
152152
'r.browser.openExternal': session.openExternalBrowser,
153+
'r.dataview.refresh': session.refreshDataViewPanel,
153154

154155
// (help related commands are registered in rHelp.initializeHelp)
155156
};

0 commit comments

Comments
 (0)