@@ -67,6 +67,130 @@ if (is.null(getOption("help_type"))) {
6767}
6868
6969use_webserver <- isTRUE(getOption(" vsc.use_webserver" , FALSE ))
70+
71+ get_column_def <- function (name , field , value ) {
72+ filter <- TRUE
73+ tooltip <- sprintf(
74+ " %s, class: [%s], type: %s" ,
75+ name ,
76+ toString(class(value )),
77+ typeof(value )
78+ )
79+ if (is.numeric(value )) {
80+ type <- " numericColumn"
81+ if (is.null(attr(value , " class" ))) {
82+ filter <- " agNumberColumnFilter"
83+ }
84+ } else if (inherits(value , " Date" )) {
85+ type <- " dateColumn"
86+ filter <- " agDateColumnFilter"
87+ } else {
88+ type <- " textColumn"
89+ filter <- " agTextColumnFilter"
90+ }
91+ list (
92+ headerName = name ,
93+ headerTooltip = tooltip ,
94+ field = field ,
95+ type = type ,
96+ filter = filter
97+ )
98+ }
99+
100+ dataview_table <- function (data , start = 0 , end = NULL , sortModel = NULL ) {
101+
102+ if (is.matrix(data )) {
103+ data <- as.data.frame.matrix(data )
104+ }
105+ if (! is.data.frame(data )) {
106+ stop(" data must be a data.frame or a matrix" )
107+ }
108+
109+ data.table :: setDT(data )
110+
111+ # number of rows & original column names
112+ .nrow <- nrow(data )
113+ .colnames <- colnames(data )
114+ if (is.null(.colnames )) {
115+ .colnames <- sprintf(" V%d" , seq_len(ncol(data )))
116+ } else {
117+ .colnames <- trimws(.colnames )
118+ }
119+
120+ # capture or generate rownames
121+ if (.row_names_info(data ) > 0L ) {
122+ rownames_ <- rownames(data )
123+ rownames(data ) <- NULL
124+ } else {
125+ rownames_ <- seq_len(.nrow )
126+ }
127+
128+ .colnames <- c(" (row)" , .colnames )
129+ fields <- sprintf(" x%d" , seq_along(.colnames ))
130+
131+ # map x1→"(row)", x2→first real col, …
132+ field_map <- setNames(.colnames , fields )
133+
134+ # ── SORT data before slicing ──
135+ if (! is.null(sortModel ) && length(sortModel ) > 0 ) {
136+
137+ sort <- sortModel [[1 ]]
138+ col_f <- sort $ colId
139+ dir <- sort $ sort
140+ real <- field_map [[col_f ]]
141+
142+ # only sort if it's one of your real data columns
143+ if (! is.null(real ) && real %in% .colnames [- 1 ]) {
144+
145+ # attach rownames_ as a helper column
146+ data [, " __rownames__" : = rownames_ ]
147+
148+ # sort in place: order=1L for asc, -1L for desc
149+ data.table :: setorderv(
150+ data ,
151+ cols = real ,
152+ order = if (dir == " asc" ) 1L else - 1L
153+ )
154+
155+ # pull the helper back out as rownames_
156+ rownames_ <- data [[" __rownames__" ]]
157+ data [, " __rownames__" : = NULL ]
158+ }
159+ }
160+
161+ if (is.null(end )) end <- .nrow
162+ s <- as.integer(start ) + 1
163+ e <- min(.nrow , as.integer(end ))
164+
165+ if (s > .nrow || e < 1 || s > e ) {
166+ rows <- data [0 , , drop = FALSE ]
167+ rownums <- integer(0 )
168+ } else {
169+ rows <- data [s : e , , drop = FALSE ]
170+ rownums <- rownames_ [s : e ]
171+ }
172+
173+ rows <- c(list (" " = rownums ), .subset(rows ))
174+ names(rows ) <- fields
175+ class(rows ) <- " data.frame"
176+ attr(rows , " row.names" ) <- .set_row_names(length(rownums ))
177+
178+ rows <- jsonlite :: fromJSON(
179+ jsonlite :: toJSON(rows , dataframe = " rows" , na = " null" , auto_unbox = TRUE )
180+ )
181+ columns <- .mapply(
182+ get_column_def ,
183+ list (.colnames , fields , rows ),
184+ NULL
185+ )
186+
187+ list (
188+ columns = columns ,
189+ rows = rows ,
190+ totalRows = .nrow
191+ )
192+ }
193+
70194if (use_webserver ) {
71195 if (requireNamespace(" httpuv" , quietly = TRUE )) {
72196 request_handlers <- list (
@@ -120,6 +244,12 @@ if (use_webserver) {
120244 })
121245 return (result )
122246 }
247+ },
248+ dataview_fetch_rows = function (varname , start , end , sortModel , ... ) {
249+ obj <- get(varname , envir = .GlobalEnv )
250+ out <- dataview_table(obj , start , end , sortModel )
251+ out $ columns <- NULL
252+ return (out )
123253 }
124254 )
125255
@@ -456,76 +586,8 @@ if (use_httpgd && "httpgd" %in% .packages(all.available = TRUE)) {
456586
457587show_view <- ! identical(getOption(" vsc.view" , " Two" ), FALSE )
458588if (show_view ) {
459- # Create registry to track dataview UUIDs by title
460589 dataview_registry <- new.env(parent = emptyenv())
461590
462- get_column_def <- function (name , field , value ) {
463- filter <- TRUE
464- tooltip <- sprintf(
465- " %s, class: [%s], type: %s" ,
466- name ,
467- toString(class(value )),
468- typeof(value )
469- )
470- if (is.numeric(value )) {
471- type <- " numericColumn"
472- if (is.null(attr(value , " class" ))) {
473- filter <- " agNumberColumnFilter"
474- }
475- } else if (inherits(value , " Date" )) {
476- type <- " dateColumn"
477- filter <- " agDateColumnFilter"
478- } else {
479- type <- " textColumn"
480- filter <- " agTextColumnFilter"
481- }
482- list (
483- headerName = name ,
484- headerTooltip = tooltip ,
485- field = field ,
486- type = type ,
487- filter = filter
488- )
489- }
490-
491- dataview_table <- function (data ) {
492- if (is.matrix(data )) {
493- data <- as.data.frame.matrix(data )
494- }
495-
496- if (is.data.frame(data )) {
497- .nrow <- nrow(data )
498- .colnames <- colnames(data )
499- if (is.null(.colnames )) {
500- .colnames <- sprintf(" V%d" , seq_len(ncol(data )))
501- } else {
502- .colnames <- trimws(.colnames )
503- }
504- if (.row_names_info(data ) > 0L ) {
505- rownames <- rownames(data )
506- rownames(data ) <- NULL
507- } else {
508- rownames <- seq_len(.nrow )
509- }
510- .colnames <- c(" (row)" , .colnames )
511- fields <- sprintf(" x%d" , seq_along(.colnames ))
512- data <- c(list (" " = rownames ), .subset(data ))
513- names(data ) <- fields
514- class(data ) <- " data.frame"
515- attr(data , " row.names" ) <- .set_row_names(.nrow )
516- columns <- .mapply(get_column_def ,
517- list (.colnames , fields , data ),
518- NULL
519- )
520- list (
521- columns = columns ,
522- data = data
523- )
524- } else {
525- stop(" data must be a data.frame or a matrix" )
526- }
527- }
528-
529591 show_dataview <- function (x , title , uuid = NULL ,
530592 viewer = getOption(" vsc.view" , " Two" ),
531593 row_limit = abs(getOption(" vsc.row_limit" , 0 ))) {
@@ -615,9 +677,11 @@ if (show_view) {
615677 }
616678 if (is.data.frame(x ) || is.matrix(x )) {
617679 x <- as_truncated_data(x )
618- data <- dataview_table(x )
680+ # Get initial chunk of data (first 100 rows)
681+ meta <- dataview_table(x , start = 0 , end = 1 )
682+ meta $ rows <- list ()
619683 file <- tempfile(tmpdir = tempdir , fileext = " .json" )
620- jsonlite :: write_json(data , file , na = " string" , null = " null" , auto_unbox = TRUE , force = TRUE )
684+ jsonlite :: write_json(meta , file , na = " string" , null = " null" , auto_unbox = TRUE , force = TRUE )
621685 request(" dataview" , source = " table" , type = " json" ,
622686 title = title , file = file , viewer = viewer , uuid = uuid , dataview_uuid = dataview_uuid
623687 )
@@ -690,8 +754,6 @@ path_to_uri <- function(path) {
690754}
691755
692756request_browser <- function (url , title , ... , viewer ) {
693- # Printing URL with specific port triggers
694- # auto port-forwarding under remote development
695757 message(" Browsing " , url )
696758 request(" browser" , url = url , title = title , ... , viewer = viewer )
697759}
@@ -820,7 +882,6 @@ options(
820882 page_viewer = show_page_viewer
821883)
822884
823- # rstudioapi
824885rstudioapi_enabled <- function () {
825886 isTRUE(getOption(" vsc.rstudioapi" , TRUE ))
826887}
@@ -832,12 +893,11 @@ if (rstudioapi_enabled()) {
832893 file.create(response_lock_file , showWarnings = FALSE )
833894 file.create(response_file , showWarnings = FALSE )
834895 addin_registry <- file.path(dir_session , " addins.json" )
835- # This is created in attach()
836896
837897 get_response_timestamp <- function () {
838898 readLines(response_lock_file )
839899 }
840- # initialise the reponse timestamp to empty string
900+
841901 response_time_stamp <- " "
842902
843903 get_response_lock <- function () {
@@ -876,10 +936,6 @@ if (rstudioapi_enabled()) {
876936 }
877937 )
878938 if (" rstudioapi" %in% loadedNamespaces()) {
879- # if the rstudioapi is already loaded, for example via a call to
880- # library(tidyverse) in the user's profile, we need to shim it now.
881- # There's no harm in having also registered the hook in this case. It can
882- # work in the event that the namespace is unloaded and reloaded.
883939 rstudioapi_util_env $ rstudioapi_patch_hook(rstudioapi_env )
884940 }
885941
@@ -945,7 +1001,6 @@ print.hsearch <- function(x, ...) {
9451001 invisible (x )
9461002}
9471003
948- # a copy of .S3method(), since this function is new in R 4.0
9491004.S3method <- function (generic , class , method ) {
9501005 if (missing(method )) {
9511006 method <- paste(generic , class , sep = " ." )
0 commit comments