clipr/0000755000176200001440000000000015204761412011365 5ustar liggesusersclipr/tests/0000755000176200001440000000000014177762460012543 5ustar liggesusersclipr/tests/testthat/0000755000176200001440000000000015204761412014367 5ustar liggesusersclipr/tests/testthat/test-sizes.R0000644000176200001440000000057615204664772016647 0ustar liggesuserscontext("board size limits") mirror <- function(length) { longstr <- paste0(sample(letters, length, replace = TRUE), collapse = "") invisible(write_clip(longstr)) readstr <- read_clip() expect_equal(readstr, longstr) return(TRUE) } test_that("large sizes of content can be copied losslessly", { skip_if_not(is_clipr_available, skip_msg) lapply(10^(1:8), mirror) }) clipr/tests/testthat/test-render.R0000644000176200001440000001403615204664772016765 0ustar liggesuserscontext("Clipr read and write") test_that("single NA vectors don't cause error", { skip_if_not(is_clipr_available, skip_msg) expect_equivalent(write_clip(NA_character_), NA_character_) expect_equivalent(write_clip(NA_character_, return_new = TRUE), "NA") expect_warning(write_clip(NA)) expect_warning(write_clip(NA_integer_)) expect_warning(write_clip(NA_real_)) expect_warning(write_clip(NA_complex_)) }) test_that("empty character in write_clip() causes no erroneous warning", { skip_if_not(is_clipr_available, skip_msg) expect_equivalent(write_clip(""), "") expect_warning(null_res <- write_clip(NULL)) expect_equivalent(null_res, NULL) expect_warning(null_new_res <- write_clip(NULL, return_new = TRUE)) expect_equivalent(null_new_res, "") expect_equivalent(write_clip(character(0)), character(0)) expect_equivalent(write_clip(character(0), return_new = TRUE), "") expect_warning(empty_res <- write_clip(integer(0))) expect_equivalent(empty_res, integer(0)) expect_warning(empty_new_res <- write_clip(integer(0), return_new = TRUE)) expect_equivalent(empty_new_res, "") expect_silent(clear_clip()) }) test_that("Render character vectors", { skip_if_not(is_clipr_available, skip_msg) single <- "hello, world!" expect_equivalent(write_clip(single), single) }) test_that("Render default multiline vectors", { skip_if_not(is_clipr_available, skip_msg) multiline <- c("hello", "world!") inv_out <- write_clip(multiline, return_new = TRUE) if (sys_type() == "Windows") { expect_equivalent(inv_out, "hello\r\nworld!") } else { expect_equivalent(inv_out, "hello\nworld!") } expect_equivalent(read_clip(), multiline) }) test_that("Render custom multiline vectors", { skip_if_not(is_clipr_available, skip_msg) multiline <- c("hello", "world!") inv_out <- write_clip(multiline, breaks = ", ", return_new = TRUE) expect_equivalent(inv_out, "hello, world!") expect_equivalent(read_clip(), inv_out) }) test_that("Render default data.frames", { skip_if_not(is_clipr_available, skip_msg) tbl <- data.frame(a = c(1,2,3), b = c(4,5,6)) inv_out <- write_clip(tbl, return_new = TRUE) if (sys_type() == "Windows") { expect_equivalent(inv_out, "a\tb\r\n1\t4\r\n2\t5\r\n3\t6") } else { expect_equivalent(inv_out, "a\tb\n1\t4\n2\t5\n3\t6") } expect_equal(read_clip_tbl(), tbl) }) test_that("Probable rownames are read", { skip_if_not(is_clipr_available, skip_msg) write_clip(mtcars) expect_equal(read_clip_tbl(), mtcars) }) test_that("read_clip_tbl handles content without trailing newline", { skip_if_not(is_clipr_available, skip_msg) x <- c("Name's\tAge", "Alice\t30", "Bob\t25") tbl <- read_clip_tbl(x) expect_equal(nrow(tbl), 2) expect_equal(ncol(tbl), 2) expect_equal(tbl[[1]], c("Alice", "Bob")) expect_equal(tbl[[2]], c(30, 25)) x_no_special <- c("Name\tValue", "foo\t42") tbl2 <- read_clip_tbl(x_no_special) expect_equal(nrow(tbl2), 1) expect_equal(tbl2[[1]], "foo") expect_equal(tbl2[[2]], 42L) }) test_that("Render custom data.frames", { skip_if_not(is_clipr_available, skip_msg) tbl <- data.frame(a = c(1,2,3), b = c(4,5,6)) inv_out <- write_clip(tbl, sep = ",", return_new = TRUE) if (sys_type() == "Windows") { expect_equivalent(inv_out, "a,b\r\n1,4\r\n2,5\r\n3,6") } else { expect_equivalent(inv_out, "a,b\n1,4\n2,5\n3,6") } expect_equivalent(read_clip(), c("a,b", "1,4", "2,5", "3,6")) }) test_that("Render matricies", { skip_if_not(is_clipr_available, skip_msg) tbl <- matrix(c(1, 2, 3, 4, 5, 6), nrow = 3, ncol = 2) inv_out <- write_clip(tbl, return_new = TRUE) if (sys_type() == "Windows") { expect_equivalent(inv_out, "1\t4\r\n2\t5\r\n3\t6") } else { expect_equivalent(inv_out, "1\t4\n2\t5\n3\t6") } expect_equivalent(read_clip(), c("1\t4", "2\t5", "3\t6")) }) test_that("Render custom matricies", { skip_if_not(is_clipr_available, skip_msg) tbl <- matrix(c(1, 2, 3, 4, 5, 6), nrow = 3, ncol = 2) inv_out <- write_clip(tbl, sep = ",", return_new = TRUE) if (sys_type() == "Windows") { expect_equivalent(inv_out, "1,4\r\n2,5\r\n3,6") } else { expect_equivalent(inv_out, "1,4\n2,5\n3,6") } expect_equivalent(read_clip(), c("1,4", "2,5", "3,6")) }) test_that("Render tables read from clipboard as data.frames", { skip_if_not(is_clipr_available, skip_msg) inv_out <- write_clip(iris[1:2, 1:4], return_new = TRUE) expect_equivalent(read_clip_tbl(), iris[1:2, 1:4]) }) test_that("Tables written with rownames add extra space for column names", { skip_if_not(is_clipr_available, skip_msg) d <- matrix(1:4, 2) rownames(d) <- c('a','b') colnames(d) <- c('c','d') df <- data.frame(c = c(1, 2), d = c(3, 4)) rownames(df) <- c('a', 'b') mat_rnames_out <- write_clip(d, row.names = TRUE, col.names = FALSE, return_new = TRUE) df_rnames_out <- write_clip(df, row.names = TRUE, col.names = FALSE, return_new = TRUE) if (sys_type() == "Windows") { expect_equivalent(mat_rnames_out, "a\t1\t3\r\nb\t2\t4") expect_equivalent(df_rnames_out, "a\t1\t3\r\nb\t2\t4") } else { expect_equivalent(mat_rnames_out, "a\t1\t3\nb\t2\t4") expect_equivalent(df_rnames_out, "a\t1\t3\nb\t2\t4") } mat_bnames_out <- write_clip(d, row.names = TRUE, col.names = TRUE, return_new = TRUE) df_bnames_out <- write_clip(df, row.names = TRUE, col.names = TRUE, return_new = TRUE) if (sys_type() == "Windows") { expect_equivalent(mat_bnames_out, "\tc\td\r\na\t1\t3\r\nb\t2\t4") expect_equivalent(df_bnames_out, "\tc\td\r\na\t1\t3\r\nb\t2\t4") } else { expect_equivalent(mat_bnames_out, "\tc\td\na\t1\t3\nb\t2\t4") expect_equivalent(df_bnames_out, "\tc\td\na\t1\t3\nb\t2\t4") } mat_nonames_out <- write_clip(d, row.names = FALSE, col.names = FALSE, return_new = TRUE) df_nonames_out <- write_clip(df, row.names = FALSE, col.names = FALSE, return_new = TRUE) if (sys_type() == "Windows") { expect_equivalent(mat_nonames_out, "1\t3\r\n2\t4") expect_equivalent(df_nonames_out, "1\t3\r\n2\t4") } else { expect_equivalent(mat_nonames_out, "1\t3\n2\t4") expect_equivalent(df_nonames_out, "1\t3\n2\t4") } }) clipr/tests/testthat/test-systems.R0000644000176200001440000000151614177762460017215 0ustar liggesuserscontext("systems") test_that("utility checking works on Linux-like", { if (identical(Sys.getenv("CLIP_TYPE"), "xclip")) { expect_true(has_xclip()) expect_false(has_xsel()) expect_false(has_wl_clipboard()) } if (identical(Sys.getenv("CLIP_TYPE"), "xsel")) { expect_false(has_xclip()) expect_true(has_xsel()) expect_false(has_wl_clipboard()) } if (identical(Sys.getenv("CLIP_TYPE"), "wayland")) { expect_false(has_xclip()) expect_false(has_xsel()) expect_true(has_wl_clipboard()) } if (identical(Sys.getenv("CLIP_TYPE"), "none")) { expect_false(has_xclip()) expect_false(has_xsel()) expect_false(has_wl_clipboard()) } if (identical(Sys.getenv("CLIP_TYPE"), "nodisplay")) { expect_error(has_xclip()) expect_false(has_xsel()) expect_false(has_wl_clipboard()) } }) clipr/tests/testthat/test-diagnostics.R0000644000176200001440000000414314177762460020014 0ustar liggesuserscontext("diagnostics") test_that("clipr_available fails when DISPLAY is not configured; succeeds when it is", { # Only run this test on Github Actions skip_if_not(identical(Sys.getenv("GITHUB_ACTIONS"), "true")) # If this envar hasn't been set, confirm that is_clipr_available will be false # and write_clip will error if (identical(Sys.getenv("CLIPR_ALLOW"), "")) { expect_false(is_clipr_available) expect_error(write_clip("test")) } else { if (identical(Sys.getenv("CLIP_TYPE"), "none")) expect_false(is_clipr_available) if (identical(Sys.getenv("CLIP_TYPE"), "xclip")) expect_true(is_clipr_available) if (identical(Sys.getenv("CLIP_TYPE"), "xsel")) expect_true(is_clipr_available) if (identical(Sys.getenv("CLIP_TYPE"), "wayland")) expect_true(is_clipr_available) } }) test_that("dr_clipr provides informative messages", { if (identical(Sys.getenv("CLIPR_ALLOW"), "")) { expect_message(dr_clipr(), "CLIPR_ALLOW", fixed = TRUE) } else { if (identical(Sys.getenv("CLIP_TYPE"), "xclip")) expect_message(dr_clipr(), msg_clipr_available(), fixed = TRUE) if (identical(Sys.getenv("CLIP_TYPE"), "xsel")) expect_message(dr_clipr(), msg_clipr_available(), fixed = TRUE) if (identical(Sys.getenv("CLIP_TYPE"), "wayland")) expect_message(dr_clipr(), msg_clipr_available(), fixed = TRUE) if (identical(Sys.getenv("CLIP_TYPE"), "none")) expect_message(dr_clipr(), msg_no_clipboard(), fixed = TRUE) if (identical(Sys.getenv("CLIP_TYPE"), "nodisplay")) expect_message(dr_clipr(), msg_no_display(), fixed = TRUE) expect_true(grepl("has read/write access", msg_clipr_available())) expect_true(grepl("requires 'xclip'", msg_no_clipboard())) expect_true(grepl("requires that the DISPLAY", msg_no_display())) } }) test_that("Unavailable clipboard throws warning", { if (!is_clipr_available) { expect_error(write_clip("a")) } }) test_that("clipr_available() does not overwrite existing contents", { skip_if_not(is_clipr_available, skip_msg) write_clip("z") clipr_available() expect_equal(read_clip(), "z") }) clipr/tests/testthat/setup.R0000644000176200001440000000027614177762460015673 0ustar liggesusers# Setup for all following tests skip_msg <- "System clipboard is not available - skipping test." is_clipr_available <- clipr_available() message("Is clipr available?: ", is_clipr_available) clipr/tests/testthat.R0000644000176200001440000000006614177762460014530 0ustar liggesuserslibrary(testthat) library(clipr) test_check("clipr") clipr/MD50000644000176200001440000000341515204761412011700 0ustar liggesusers3bafd58545637ec3cd2e6d4c2dd16eeb *DESCRIPTION ac9216bb379e4dad41fcf47ac889c3d9 *NAMESPACE 062c3cb938f46fa256a0af188bda8dbd *NEWS.md 6ee0c8698848c0addff943bfc710d40d *R/clipboard.R 03219652ae469c8ec2e5e96ff1b2869a *R/clipr-package.R c3673645d26e307510e4b9092022ab7b *R/clipr_addin.R 78462ea037dad6dc795301e220542f80 *R/flat_str.R ddff6f89ced650b31314fe1b65363cb3 *R/linux_clipboard.R 127954870f38794f4b2671fc08623ac6 *R/osx_clipboard.R 65eca155cdc64d300d8f4b773bf2b4fd *R/read_clip_tbl.R 453049b87c715b158f0d4ed13721acc4 *R/utils.R 5b9bbc21d44d557fedf004203fb90608 *R/win_clipboard.R af5151a5efbf1748b49308a1d2909840 *README.md 3ba964820385d40779005d48acf758ab *build/vignette.rds 46750e778a5cdb4d65c347f8e43df623 *inst/doc/developing-with-clipr.R 84e33d5522227cda21ffbb2c43045ee9 *inst/doc/developing-with-clipr.Rmd 9aa4255a8359053bf070e72698d1fc4d *inst/doc/developing-with-clipr.html c5d91ccff2716bd64fd3dbf351507c07 *inst/rstudio/addins.dcf f8c1c7e8cb9612e9c3d58455491fba2b *man/clear_clip.Rd 174446c94f807cae4fd98bc2b50dfbf9 *man/clipr-package.Rd 6b96b4408b24ad452c8d4b6fff88494c *man/clipr.Rd 9ff95009c8aa71675ae5d2e6513d0e64 *man/clipr_available.Rd 0441a3c453b0e77192e8f1cd05283f3b *man/read_clip.Rd 394e6434b0bcea480cd4bf8a8f5cf0a8 *man/read_clip_tbl.Rd 489abf9df00f253fa3cbfe5eba454636 *man/write_clip.Rd 9ad848459b1749b5a5a26c74d9db944e *man/write_last_clip.Rd ec77100d776b5924e0da206268d2517d *tests/testthat.R 51d8d49a44ccf1bc6771a64ecc6a4d22 *tests/testthat/setup.R 7e6583d8339882002b75ffacb6b2abd0 *tests/testthat/test-diagnostics.R 3ae9ae3888abba50affaee7e0e516496 *tests/testthat/test-render.R 2e19246605141349be96068359a21aab *tests/testthat/test-sizes.R 9fb913b103141779463f88542abb69e1 *tests/testthat/test-systems.R 84e33d5522227cda21ffbb2c43045ee9 *vignettes/developing-with-clipr.Rmd clipr/R/0000755000176200001440000000000015204664772011601 5ustar liggesusersclipr/R/clipr-package.R0000644000176200001440000000115715204664772014432 0ustar liggesusers#' @keywords internal "_PACKAGE" ## usethis namespace: start #' clipr: Read and Write from the System Clipboard #' #' Simple utility functions to read from and write to the Windows, OS X, and X11 #' clipboards. #' #' The basic functions [read_clip()] and [write_clip()] wrap #' platform-specific functions for writing values from R to the system #' clipboard. [read_clip_tbl()] will attempt to process the clipboard #' content like a table copied from a spreadsheet program. #' #' [clipr_available()] is useful when building packages that #' depend on clipr functionality. #' #' @name clipr ## usethis namespace: end NULL clipr/R/linux_clipboard.R0000644000176200001440000000632115204664772015104 0ustar liggesusers# Determine if a given utility is installed AND accessible # Takes a character vector whose first element is the name of the # utility executable and whose subsequent elements are command-line # arguments to the utility for the test run. has_util <- function(util_test) { if (nzchar(Sys.which(util_test[1]))) { # If utility is accessible, check that DISPLAY can be opened. try_res <- tryCatch( system2(util_test[1], util_test[-1], stdout = TRUE, stderr = FALSE), error = function(c) { print(c) return(FALSE) }, warning = function(c) { print(c) return(FALSE) } ) # In the case of an error/warning on trying the function, then the util is # not available if (identical(try_res, FALSE)) { notify_no_display() } else { TRUE } } else { FALSE } } # Determine if system has 'xclip' installed AND it's accessible has_xclip <- function() has_util(c("xclip", "-o", "-selection", "clipboard")) # Determine if system has 'xsel' installed has_xsel <- function() has_util(c("xsel", "--clipboard", "--output")) # Determine if system has both 'wl-paste' and 'wl-copy' installed has_wl_clipboard <- function() has_wl_paste() & has_wl_copy() # Determine if system has 'wl-paste' installed has_wl_paste <- function() has_util(c("wl-paste", "--primary")) # Determine if system has 'wl-copy' installed has_wl_copy <- function() has_util(c("wl-copy", "--help")) # Stop read/write and return an error of missing clipboard software. notify_no_cb <- function() { stop(msg_no_clipboard(), call. = FALSE) } notify_no_display <- function() { stop(msg_no_display(), call. = FALSE) } # Helper function to read from the X11 clipboard # # Requires the utility 'xclip' or 'xsel' when using X11, or 'wl-paste' when # using Wayland. This function will stop with an error if neither is found. # Adapted from: # https://github.com/mrdwab/overflow-mrdwab/blob/master/R/readClip.R and: # https://github.com/jennybc/reprex/blob/master/R/clipboard.R X11_read_clip <- function() { if (has_xclip()) { con <- pipe("xclip -o -selection clipboard") } else if (has_xsel()) { con <- pipe("xsel --clipboard --output") } else if (has_wl_paste()) { con <- pipe("wl-paste") } else { notify_no_cb() } content <- scan(con, what = character(), sep = "\n", blank.lines.skip = FALSE, quiet = TRUE) close(con) return(content) } # Helper function to write to the X11 clipboard # # Requires the utility 'xclip' or 'xsel' when using X11, or 'wl-copy' when using # Wayland. This function will stop with an error if neither is found. Adapted # from https://github.com/mrdwab/overflow-mrdwab/blob/master/R/writeClip.R # # Targets "primary" and "clipboard" clipboards if using xclip, see: # http://unix.stackexchange.com/a/69134/89254 X11_write_clip <- function(content, object_type, breaks, eos, return_new, ...) { if (has_xclip()) { con <- pipe("xclip -i -sel p -f | xclip -i -sel c", "w") } else if (has_xsel()) { con <- pipe("xsel --clipboard --input", "w") } else if (has_wl_copy()) { con <- pipe("wl-copy", "w") } else { notify_no_cb() } .dots <- list(...) write_nix(content, object_type, breaks, eos, return_new, con, .dots) } clipr/R/read_clip_tbl.R0000644000176200001440000000311415204664772014506 0ustar liggesusers#' Transforms output of [read_clip()] into data frame. #' #' Transforms clipped content into a data frame by putting #' [read_clip()] output by using [read.table()]. #' #' @param x Defaults to reading from the clipboard, but can be substituted by a #' character vector already generated by [read_clip()]. #' @param \ldots Options to pass to [read.table()]. The following #' [read.table()] arguments will be passed by default, but can be #' overridden by specifying them when calling `read_clip_tbl`: \describe{ #' \item{`header`}{`TRUE`} #' \item{`sep`}{`"\t"`} #' \item{`row.names`}{`1`} #' \item{`stringsAsFactors`}{`FALSE`} #' \item{`na.strings`}{`c("NA", "")`} #' \item{`strip.white`}{`TRUE`} #' \item{`quote`}{`""`} } #' #' @return A data frame with the contents of the clipboard. If the system #' clipboard is empty, returns `NULL` #' #' @export read_clip_tbl <- function(x = read_clip(), ...) { if (is.null(x)) return(NULL) .dots <- list(...) .dots$file <- textConnection(paste0(paste0(x, collapse = "\n"), "\n")) if (is.null(.dots$header)) .dots$header <- TRUE if (is.null(.dots$row.names)) { if (substr(x[1], 1, 1) == "\t") { .dots$row.names <- 1 } else { .dots$row.names <- NULL } } if (is.null(.dots$sep)) .dots$sep <- "\t" if (is.null(.dots$stringsAsFactors)) .dots$stringsAsFactors <- FALSE if (is.null(.dots$na.strings)) .dots$na.strings <- c("NA", "") if (is.null(.dots$strip.white)) .dots$strip.white <- TRUE if (is.null(.dots$quote)) .dots$quote <- "" do.call(utils::read.table, args = .dots) } clipr/R/clipboard.R0000644000176200001440000001253215204670670013660 0ustar liggesusers#' Read clipboard #' #' Read the contents of the system clipboard into a character vector. #' #' @param allow_non_interactive By default, clipr will throw an error if run in #' a non-interactive session. Set the environment variable #' `CLIPR_ALLOW=TRUE` in order to override this behavior. #' #' @return A character vector with the contents of the clipboard. If the system #' clipboard is empty, returns NULL #' #' @note [read_clip()] will not try to guess at how to parse copied text. If #' you are copying tabular data, it is suggested that you use #' [read_clip_tbl()]. #' #' @examples #' \dontrun{ #' clip_text <- read_clip() #' } #' #' @export read_clip <- function(allow_non_interactive = Sys.getenv("CLIPR_ALLOW", interactive())) { if (allow_non_interactive != "TRUE") error_interactive() # Determine system type sys.type <- sys_type() # Use the appropriate handler function chosen_read_clip <- switch(sys.type, "Darwin" = osx_read_clip, "Windows" = win_read_clip, X11_read_clip ) content <- chosen_read_clip() if (length(content) == 0) { warning("System clipboard contained no readable text. Returning NULL.") return(NULL) } content } #' Write clipboard #' #' Write a character vector to the system clipboard #' #' @inheritParams read_clip #' #' @param content An object to be written to the system clipboard. #' @param object_type [write_clip()] tries to be smart about writing objects in a #' useful manner. If passed a data.frame or matrix, it will format it using #' [write.table()] for pasting into an external spreadsheet program. #' It will otherwise coerce the object to a character vector. `auto` will #' check the object type, otherwise `table` or `character` can be #' explicitly specified. #' @param breaks The separator to be used between each element of the character #' vector being written. `NULL` defaults to writing system-specific line #' breaks between each element of a character vector, or each row of a table. #' @param eos The terminator to be written after each string, followed by an #' ASCII `nul`. Defaults to no terminator character, indicated by #' `NULL`. #' @param return_new If true, returns the rendered string; if false, returns the #' original object #' @param ... Custom options to be passed to [write.table()] (if `x` is a #' table-like). Defaults to sane line-break and tab standards based on the #' operating system. By default, this will use `col.names = TRUE` if the table #' object has column names, and `row.names = TRUE` if the object has row names #' other than `c("1", "2", "3"...)`. Override these defaults by passing #' arguments here. #' #' @note On X11 systems, [write_clip()] will cause either xclip (preferred) or #' xsel to be called. Be aware that, by design, these processes will fork into #' the background. They will run until the next paste event, when they will #' then exit silently. (See the man pages for #' [xclip](https://linux.die.net/man/1/xclip) and #' [xsel](https://www.vergenet.net/~conrad/software/xsel/xsel.1x.html#notes) #' for more on their behaviors.) However, this means that even if you #' terminate your R session after running [write_clip()], those processes will #' continue until you access the clipboard via another program. This may be #' expected behavior for interactive use, but is generally undesirable for #' non-interactive use. For this reason you must not run [write_clip()] on #' CRAN, as the nature of xsel [has caused issues in the #' past](https://github.com/mdlincoln/clipr/issues/38). #' #' Call [clipr_available()] to safely check whether the clipboard is readable #' and writable. #' #' @return Invisibly returns the original object #' #' @examples #' \dontrun{ #' text <- "Write to clipboard" #' write_clip(text) #' #' multiline <- c("Write", "to", "clipboard") #' write_clip(multiline) #' # Write #' # to #' # clipboard #' #' write_clip(multiline, breaks = ",") #' # write,to,clipboard #' #' tbl <- data.frame(a=c(1,2,3), b=c(4,5,6)) #' write_clip(tbl) #' } #' #' @export write_clip <- function(content, object_type = c("auto", "character", "table"), breaks = NULL, eos = NULL, return_new = FALSE, allow_non_interactive = Sys.getenv("CLIPR_ALLOW", interactive()), ...) { if (allow_non_interactive != "TRUE") error_interactive() object_type <- match.arg(object_type) # Determine system type sys.type <- sys_type() # Choose an operating system-specific function (stop with error if not # recognized) chosen_write_clip <- switch(sys.type, "Darwin" = osx_write_clip, "Windows" = win_write_clip, X11_write_clip ) # Supply the clipboard content to write and options list to this function invisible(chosen_write_clip(content, object_type, breaks, eos, return_new, ...)) } #' Clear clipboard #' #' Clear the system clipboard. #' #' @param \ldots Pass other options to [write_clip()]. #' #' @note This is a wrapper function for `write_clip("")` #' #' @export clear_clip <- function(...) { write_clip(content = "", ...) } #' Write contents of the last R expression to the clipboard #' #' @param \ldots Pass other options to [write_clip()]. #' #' @note This is a wrapper function for `write_clip(.Last.value)` #' @export write_last_clip <- function(...) { write_clip(.Last.value, ...) } clipr/R/osx_clipboard.R0000644000176200001440000000321614177762460014557 0ustar liggesusers# Helper function to read from the OS X clipboard # Adapted from https://github.com/jennybc/reprex/blob/master/R/clipboard.R osx_read_clip <- function() { con <- pipe("pbpaste") content <- scan(con, what = character(), sep = "\n", blank.lines.skip = FALSE, quiet = TRUE) close(con) return(content) } # Helper function to write to the OS X clipboard # Adapted from https://github.com/jennybc/reprex/blob/master/R/clipboard.R osx_write_clip <- function(content, object_type, breaks, eos, return_new, ...) { .dots <- list(...) con <- pipe("pbcopy") write_nix(content, object_type, breaks, eos, return_new, con, .dots) } # The same content rendering and writing steps are used in both OS X and Linux, # just with different connection objects write_nix <- function(content, object_type, breaks, eos, return_new, con, .dots) { # If no custom line separator has been specified, use Unix's default newline # character '\n' breaks <- ifelse(is.null(breaks), '\n', breaks) # If no custom tab separator for tables has been specified, use Unix's default # tab character: '\t' .dots$sep <- ifelse(is.null(.dots$sep), '\t', .dots$sep) # Pass the object to rendering functions before writing out to the clipboard rendered_content <- render_object(content, object_type, breaks, .dots) # Suppress pipe() warning when writing an empty string with a NULL string # ending. if (identical(rendered_content, "")) { suppressWarnings(writeChar(rendered_content, con = con, eos = eos)) } else { writeChar(rendered_content, con = con, eos = eos) } close(con) if (return_new) { rendered_content } else { content } } clipr/R/clipr_addin.R0000644000176200001440000000056414177762460014202 0ustar liggesusersclipr_result <- function() { context <- rstudioapi::getActiveDocumentContext() expr_object <- eval(parse(text = context$selection[[1]]$text)) write_clip(expr_object) } clipr_output <- function() { context <- rstudioapi::getActiveDocumentContext() expr_object <- eval(parse(text = context$selection[[1]]$text)) write_clip(utils::capture.output(expr_object)) } clipr/R/flat_str.R0000644000176200001440000000416314177762460013547 0ustar liggesusers# Check object type to determine if it will be handled as a simple table or as a # character vector render_object <- function(content, object_type, breaks, .dots) { if (object_type == "auto") object_type <- eval_object(content) switch(object_type, "table" = table_str(content, breaks, .dots), "character" = flat_str(content, breaks)) } eval_object <- function(content) { ifelse(is.data.frame(content) | is.matrix(content), "table", "character") } # If object is a table, default to a multiline string with tab separators table_str <- function(content, breaks, .dots) { # Take the system-specific collapse out of the list .dots$x <- content .dots$sep <- .dots$sep .dots$quote <- ifelse(is.null(.dots$quote), FALSE, .dots$quote) .dots$na <- ifelse(is.null(.dots$na), "", .dots$na) .dots$col.names <- ifelse(is.null(.dots$col.names), !is.null(colnames(content)), .dots$col.names) # Check if dataframe rownames are anything different than the default numbered names numbered_rownames <- all(rownames(content) == as.character(seq_along(rownames(content)))) .dots$row.names <- ifelse(is.null(.dots$row.names), ifelse(numbered_rownames, FALSE, !is.null(rownames(content))), .dots$row.names) # Writing to and reading from a temp file is much faster than using capture.output tbl_file <- tempfile() .dots$file = tbl_file do.call(utils::write.table, .dots) read_tbl <- paste0(readLines(tbl_file), collapse = breaks) unlink(tbl_file) # If row.names = TRUE and col.names = TRUE, add additional sep character to # the start of the table if (.dots$row.names & .dots$col.names) { read_tbl <- paste0(.dots$sep, read_tbl) } return(read_tbl) } # Helper function to flatten content into 1-tuple character vector (i.e. a # string) flat_str <- function(content, breaks) { if (typeof(content) != "character") { warning("Coercing content to character") content <- as.character(content) } if (length(content) < 1) { content <- "" } else if (length(content) > 1) { content <- paste0(content, collapse = breaks) } else if (is.na(content)) { content <- "NA" } return(content) } clipr/R/win_clipboard.R0000644000176200001440000000221514200235326014520 0ustar liggesusers# Helper function to read from the Windows clipboard win_read_clip <- function() { # On R >= 4.2 (built with UCRT), the default encoding is UTF-8 even on Windows. # To avoid the encoding mismatch garbles texts, use 13 (CF_UNICODETEXT), format <- if (identical(R.version$crt, "ucrt")) 13 else 1 utils::readClipboard(format = format) } # Helper function to write to the Windows clipboard win_write_clip <- function(content, object_type, breaks, eos, return_new, ...) { format <- if (identical(R.version$crt, "ucrt")) 13 else 1 .dots <- list(...) # If no custom line separator has been specified, use Windows's default # newline character '\r\n' breaks <- ifelse(is.null(breaks), '\r\n', breaks) # If no custom tab separator for tables has been specified, use Windows's # default tab character: '\t' .dots$sep <- ifelse(is.null(.dots$sep), '\t', .dots$sep) # Pass the object to rendering functions before writing out to the clipboard rendered_content <- render_object(content, object_type, breaks, .dots) utils::writeClipboard(rendered_content, format = format) if (return_new) { rendered_content } else { content } } clipr/R/utils.R0000644000176200001440000000624414177762460013073 0ustar liggesusers.onAttach <- function(libname, pkgname) { packageStartupMessage("Welcome to clipr. See ?write_clip for advisories on writing to the clipboard in R.") } # Determine system type sys_type <- function() { return(Sys.info()["sysname"]) } #' Is the system clipboard available? #' #' Checks to see if the system clipboard is write-able/read-able. This may be #' useful if you are developing a package that relies on clipr and need to #' ensure that it will skip tests on machines (e.g. CRAN, Travis) where the #' system clipboard may not be available. #' #' @note This will automatically return `FALSE`, without even performing the #' check, if you are running in a non-interactive session. If you must call #' this non-interactively, be sure to call using #' `clipr_available(allow_non_interactive = TRUE)`, or by setting the #' environment variable `CLIPR_ALLOW=TRUE`. **Do not attempt to run #' clipr non-interactively on CRAN; this will result in a failed build!** #' #' @param \ldots Pass other options to [`write_clip()`]. Generally only used to #' pass the argument `allow_non_interactive_use = TRUE`. #' #' @return `clipr_available` returns a boolean value. #' #' @examples #' \dontrun{ #' # When using testthat: #' library(testthat) #' skip_if_not(clipr_available()) #' } #' #' @export clipr_available <- function(...) { clipr_results_check(clipr_available_handler(...)) } #' @rdname clipr_available #' #' @return Prints an informative message to the console with #' software and system configuration requirements if clipr is not available #' (invisibly returns the same string) #' #' @export dr_clipr <- function(...) { res <- clipr_available_handler(...) if (clipr_results_check(res)) { msg <- msg_clipr_available() } else { msg <- attr(res$write, which = "condition", exact = TRUE)$message } message(msg) invisible(msg) } clipr_available_handler <- function(...) { # Do not even do a check unless user has explicitly set CLIPR_ALLOW if (!interactive()) { clipr_allow <- as.logical(Sys.getenv("CLIPR_ALLOW", "FALSE")) if (!clipr_allow) { fake_write_attempt <- try(stop("CLIPR_ALLOW has not been set, so clipr will not run interactively"), silent = TRUE) return(list(write = fake_write_attempt)) } } suppressWarnings({ read_attempt <- try(read_clip(...), silent = TRUE) write_attempt <- try(write_clip(read_attempt, ...), silent = TRUE) }) return(list(read = read_attempt, write = write_attempt)) } clipr_results_check <- function(res) { if (inherits(res$write, "try-error")) return(FALSE) if (inherits(res$read, "try-error")) return(FALSE) TRUE } msg_clipr_available <- function() "clipr has read/write access to the system clipboard!" msg_no_clipboard <- function() "Clipboard on X11 requires 'xclip' (recommended) or 'xsel'; Clipboard on Wayland requires 'wl-copy' and 'wl-paste'." msg_no_display <- function() "Clipboard on X11 requires that the DISPLAY envvar be configured." msg_interactive <- function() "To run write_clip() in non-interactive mode, either call write_clip() with allow_non_interactive = TRUE, or set the environment variable CLIPR_ALLOW=TRUE" error_interactive <- function() { stop(msg_interactive()) } clipr/vignettes/0000755000176200001440000000000015204754132013376 5ustar liggesusersclipr/vignettes/developing-with-clipr.Rmd0000644000176200001440000000631614200536221020254 0ustar liggesusers--- title: "Developing with clipr" author: "Matthew Lincoln" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Developing with clipr} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ## Calling clipr safely To check whether the system has been properly configured to allow access to the clipboard, you may run `clipr_available()` which will either return `TRUE` or `FALSE`. This will be particularly useful for Linux-based systems, where clipr's functionality depends on the installation of additional software. If you wish to display system requirements and configuration messages to X11 and Wayland users, `dr_clipr()` will print these. ## Interactive & non-interactive use If you use clipr in your own package, **you must not try to call it in non-interactive sessions**, as this goes against [CRAN repository policy](https://cran.r-project.org/web/packages/policies.html): > Packages should not write in the user’s home filespace (including clipboards), nor anywhere else on the file system apart from the R session’s temporary directory (or during installation in the location pointed to by TMPDIR: and such usage should be cleaned up). Installing into the system’s R installation (e.g., scripts to its bin directory) is not allowed. > > Limited exceptions may be allowed in interactive sessions if the package obtains confirmation from the user. For this reason, `write_clip()` will error by default in non-interactive use, which includes CRAN tests. If you want to use `write_clip()` non-interactively, you may either set the environment variable `CLIPR_ALLOW=TRUE` or call `write_clip(..., allow_non_interactive = TRUE)`. ## Testing on CRAN and CI A few best practices will also help you responsibly test your clipr-using package on headless systems like CRAN or other testing infrastructure like Travis: 1. Examples that will try to use `read_clip()` or `write_clip()` ought to be wrapped in `\dontrun{}` 2. Tests calling clipr should be conditionally skipped, based on the output of `clipr_available()`. This is necessary to pass CRAN checks, as otherwise `write_clip` will error out. 3. If you are using a headless system to check your package build on Linux, consult the [GitHub Actions workflow](https://github.com/mdlincoln/clipr/blob/main/.github/workflows/R-CMD-check.yaml) for this package, which includes code for setting the `DISPLAY` and `CLIPR_ALLOW` environment variables, installing `xclip` and `xsel`, and running a pre-build script that will set up `xclip`/`xsel` to run headlessly under XVFB. ## Using clipr with Shiny clipr won't do what you expect when you call it with Shiny. clipr talks to the clipboard of the _system that is running R_. If you create a Shiny app and tell one of its functions to either read from or write to the clipboard, it can only access the clipboard of the server it is running on. R running on the _remote_ server has no way to access the _local_ clipboard belonging to your end user. However, you can instruct the user's _internet browser_ to write to the user's clipboard by using [rclipboard](https://cran.r-project.org/package=rclipboard). clipr/NAMESPACE0000644000176200001440000000027514204050253012601 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(clear_clip) export(clipr_available) export(dr_clipr) export(read_clip) export(read_clip_tbl) export(write_clip) export(write_last_clip) clipr/NEWS.md0000644000176200001440000001413615204667020012470 0ustar liggesusers## clipr 0.8.1 - Fix `read_clip_tbl()` error with trailing newline and quote characters — append a trailing newline to clipboard content before passing to `read.table()`, and set default `quote=""` to prevent single quotes in headers from being interpreted as quote delimiters (#77) - Check for `wl-copy` non-destructively on Wayland systems, fixing clipboard detection issues (#75, @danielvartan) - Skip tests if clipr is not available (e.g. on CRAN build servers without a display) ## clipr 0.8.0 - Add handlers for using the clipboard on systems using [Wayland](https://wayland.freedesktop.org/) via [wl-clipboard](https://github.com/bugaevc/wl-clipboard). Thank you to @nacnudus for the PR. - For R >= 4.2, `write_clip()` calls on Windows are modified to work well with R's shift to supporting UTF-8 as a native encoding on Windows. Thank you to @yutannihilation for the PR. Read more here: - Moved CI off of Travis and on to GitHub Actions - Clipr now has a pkgdown site at ## clipr 0.7.1 - Call xsel with the `--output` flag, which prevents RStudio from hanging when calling clipr functions on a system running certain Linux window managers. Thank you to @cgillespie and @kevinushey for identifying the bug and the solution, and to @hannahcgunderman for help in testing. ## clipr 0.7.0 Thank you to @jennybc for prompting these changes: - Before attempting to read/write form the clipboard, `clipr_available()` will first explicitly check if it is being run non-interactively, and if so, if the `CLIPR_ALLOW` environment variable has been set. This will hopefully prevent starting spurious Linux processes during CRAN tests. - Out of an abundance of caution, `read_clip()` now does the same interactive/envvar check that `write_clip()` does. - Some documentation clarifications ## clipr 0.6.0 Thank you to @wangyuchen for making the following suggestions: - To make clipr more pipe-friendly, `write_clip()` now defaults to `return_new = FALSE`, and will instead return the initial object that was passed in. To get the old behavior, pass `return_new = TRUE` - In an effort to make `write_clip()` and `read_clip_tbl()` more symmetrical, `write_clip()` now defaults to writing out row and column names when they exist. - Introduces `write_last_clip()`, a wrapper function for `write_clip(.Last.value)` ## clipr 0.5.0 - To comply with CRAN policy, `write_clip()` will now error by default if run in a non-interactive session. Non-interactive use must be explicitly enabled by setting an environment variable `CLIPR_ALLOW=TRUE`. - Documented that the default behavior when writing matrices to `write_clip()` is `col.names = FALSE` ## clipr 0.4.1 - Correct a formatting error by adding and separation character to tables when they are being written with rownames. ## clipr 0.4.0 - Introduces `dr_clipr()`, which gives informative suggestions for software and configuration requirements when accessing the clipboard on X11-based systems. ## clipr 0.3.3 - Due to poor testing and configuration options, clipr was not delivering on its promised support for xsel :( This has now been fixed, with more complete Travis tests, and some core fixes by @milesmcbain. ## clipr 0.3.2 - Suppress an erroneous warning on OS X / X11 systems when trying to write an empty string to the clipboard. - Fix error when `NA` is passed to `write_clip()`. This will now write `"NA"` to the clipboard. - Fix error when passing `NULL` or an empty vector (e.g. `character(0)`). This will now write `""` to the clipboard. ## clipr 0.3.1 - Fixes a breaking bug that caused `clipr_available` to erroneously return `FALSE`. Thank you to @krivit for catching this. - Introduces better testing of `clipr_available` to properly evaluate it on Travis CI. ## clipr 0.3.0 - Introduces `clipr_available` which checks to see if the system clipboard is writeable/readable. This may be useful if you are developing a package that relies on clipr and need to ensure that it will skip tests on machines (e.g. CRAN, Travis) where the system clipboard may not be available. Thank you to @jennybc for this suggestion. - Implements genuine testing of clipr functionality with thanks to some deft environment variable settings added by @jennybc. - Two RStudio addins: one to copy the _value_ returned when a highlighted expression is evaluated, and another that copies the _console output_. ## clipr 0.2.1 - Introduces `read_clip_tbl`, a convenience function that takes tab-delimited text from `read_clip` (such as that copied from a spreadsheet) and parses it with `read.table`. Thank you to Steve Simpson (@data-steve) for the original PR. - `write_clip(object_type = "table")` has a new internal implementation (writing to a temporary file rather than using `capture.output`) which should dramatically shorten the time it takes to write very large tables to the clipboard. Thank you to @r2evans for this suggestion. ## clipr 0.2.0 - Several changes to `write_clip` - The separator to be used when writing a character vector can now be explicitly declared using `breaks`. `breaks=NULL` will default to system-specific line breaks for both vectors and tables. - `write_clip` will default to formatting data.frames and matrices with `write.table`, allowing easy pasting of tabular objects into programs like Excel. Option `object_type="auto"` will check the object type to decide on the correct formatting, or the user may explicitly state `object_type="table"` or `object_type="character"`. - clipr will default to sane system-specific options for `write.table()`, however you may pass any custom desired options via `write_clip` - `return_new=TRUE` (the default behavior) will return the formatted character string that was passed to the system clipboard, while `write_clip(return_new=FALSE)` will return the original object. - Introduces `clear_clip`, a wrapper function for `write_clip("")` for easy clearing of the system clipboard. ## clipr 0.1.1 - Bug fix that removes the explicit test for "Linux" in favor of a check for "xclip" or "xsel" clipr/inst/0000755000176200001440000000000015204754130012341 5ustar liggesusersclipr/inst/doc/0000755000176200001440000000000015204754130013106 5ustar liggesusersclipr/inst/doc/developing-with-clipr.Rmd0000644000176200001440000000631614200536221017766 0ustar liggesusers--- title: "Developing with clipr" author: "Matthew Lincoln" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Developing with clipr} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ## Calling clipr safely To check whether the system has been properly configured to allow access to the clipboard, you may run `clipr_available()` which will either return `TRUE` or `FALSE`. This will be particularly useful for Linux-based systems, where clipr's functionality depends on the installation of additional software. If you wish to display system requirements and configuration messages to X11 and Wayland users, `dr_clipr()` will print these. ## Interactive & non-interactive use If you use clipr in your own package, **you must not try to call it in non-interactive sessions**, as this goes against [CRAN repository policy](https://cran.r-project.org/web/packages/policies.html): > Packages should not write in the user’s home filespace (including clipboards), nor anywhere else on the file system apart from the R session’s temporary directory (or during installation in the location pointed to by TMPDIR: and such usage should be cleaned up). Installing into the system’s R installation (e.g., scripts to its bin directory) is not allowed. > > Limited exceptions may be allowed in interactive sessions if the package obtains confirmation from the user. For this reason, `write_clip()` will error by default in non-interactive use, which includes CRAN tests. If you want to use `write_clip()` non-interactively, you may either set the environment variable `CLIPR_ALLOW=TRUE` or call `write_clip(..., allow_non_interactive = TRUE)`. ## Testing on CRAN and CI A few best practices will also help you responsibly test your clipr-using package on headless systems like CRAN or other testing infrastructure like Travis: 1. Examples that will try to use `read_clip()` or `write_clip()` ought to be wrapped in `\dontrun{}` 2. Tests calling clipr should be conditionally skipped, based on the output of `clipr_available()`. This is necessary to pass CRAN checks, as otherwise `write_clip` will error out. 3. If you are using a headless system to check your package build on Linux, consult the [GitHub Actions workflow](https://github.com/mdlincoln/clipr/blob/main/.github/workflows/R-CMD-check.yaml) for this package, which includes code for setting the `DISPLAY` and `CLIPR_ALLOW` environment variables, installing `xclip` and `xsel`, and running a pre-build script that will set up `xclip`/`xsel` to run headlessly under XVFB. ## Using clipr with Shiny clipr won't do what you expect when you call it with Shiny. clipr talks to the clipboard of the _system that is running R_. If you create a Shiny app and tell one of its functions to either read from or write to the clipboard, it can only access the clipboard of the server it is running on. R running on the _remote_ server has no way to access the _local_ clipboard belonging to your end user. However, you can instruct the user's _internet browser_ to write to the user's clipboard by using [rclipboard](https://cran.r-project.org/package=rclipboard). clipr/inst/doc/developing-with-clipr.R0000644000176200001440000000021715204754130017445 0ustar liggesusers## ----setup, include = FALSE--------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) clipr/inst/doc/developing-with-clipr.html0000644000176200001440000002051315204754130020211 0ustar liggesusers Developing with clipr

Developing with clipr

Matthew Lincoln

2026-05-24

Calling clipr safely

To check whether the system has been properly configured to allow access to the clipboard, you may run clipr_available() which will either return TRUE or FALSE. This will be particularly useful for Linux-based systems, where clipr’s functionality depends on the installation of additional software. If you wish to display system requirements and configuration messages to X11 and Wayland users, dr_clipr() will print these.

Interactive & non-interactive use

If you use clipr in your own package, you must not try to call it in non-interactive sessions, as this goes against CRAN repository policy:

Packages should not write in the user’s home filespace (including clipboards), nor anywhere else on the file system apart from the R session’s temporary directory (or during installation in the location pointed to by TMPDIR: and such usage should be cleaned up). Installing into the system’s R installation (e.g., scripts to its bin directory) is not allowed.

Limited exceptions may be allowed in interactive sessions if the package obtains confirmation from the user.

For this reason, write_clip() will error by default in non-interactive use, which includes CRAN tests.

If you want to use write_clip() non-interactively, you may either set the environment variable CLIPR_ALLOW=TRUE or call write_clip(..., allow_non_interactive = TRUE).

Testing on CRAN and CI

A few best practices will also help you responsibly test your clipr-using package on headless systems like CRAN or other testing infrastructure like Travis:

  1. Examples that will try to use read_clip() or write_clip() ought to be wrapped in \dontrun{}
  2. Tests calling clipr should be conditionally skipped, based on the output of clipr_available(). This is necessary to pass CRAN checks, as otherwise write_clip will error out.
  3. If you are using a headless system to check your package build on Linux, consult the GitHub Actions workflow for this package, which includes code for setting the DISPLAY and CLIPR_ALLOW environment variables, installing xclip and xsel, and running a pre-build script that will set up xclip/xsel to run headlessly under XVFB.

Using clipr with Shiny

clipr won’t do what you expect when you call it with Shiny.

clipr talks to the clipboard of the system that is running R. If you create a Shiny app and tell one of its functions to either read from or write to the clipboard, it can only access the clipboard of the server it is running on. R running on the remote server has no way to access the local clipboard belonging to your end user.

However, you can instruct the user’s internet browser to write to the user’s clipboard by using rclipboard.

clipr/inst/rstudio/0000755000176200001440000000000014177762460014047 5ustar liggesusersclipr/inst/rstudio/addins.dcf0000644000176200001440000000045714177762460015775 0ustar liggesusersName: Value to clipboard Description: Copies the results of a selected expression to the system clipboard Binding: clipr_result Interactive: false Name: Output to clipboard Description: Copies the console output of a selected expression to the system clipboard Binding: clipr_output Interactive: false clipr/README.md0000644000176200001440000000564215204664772012666 0ustar liggesusers # clipr [![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/clipr)](https://cran.r-project.org/package=clipr) [![Downloads, grand total](http://cranlogs.r-pkg.org/badges/grand-total/clipr)](https://cranlogs.r-pkg.org/) [![R-CMD-check](https://github.com/mdlincoln/clipr/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/mdlincoln/clipr/actions/workflows/R-CMD-check.yaml) [![Codecov test coverage](https://codecov.io/gh/mdlincoln/clipr/branch/master/graph/badge.svg)](https://app.codecov.io/gh/mdlincoln/clipr?branch=master) Simple utility functions to read and write from the system clipboards of Windows, OS X, and Unix-like systems (which require either xclip or xsel.) ## Installation Install from CRAN ``` r install.packages("clipr") ``` Or try the development version ``` r remotes::install_github("mdlincoln/clipr") ``` ## Usage clipr is pipe-friendly, and will default to returning the same object that was passed in. ``` r library("clipr") #> Welcome to clipr. See ?write_clip for advisories on writing to the clipboard in R. res <- write_clip(c("Text", "for", "clipboard")) res #> [1] "Text" "for" "clipboard" cb <- read_clip() cb #> [1] "Text" "for" "clipboard" ``` To capture the string that clipr writes to the clipboard, specify `return_new = TRUE`. Character vectors with length \> 1 will be collapsed with system-appropriate line breaks, unless otherwise specified ``` r cb <- write_clip(c("Text", "for", "clipboard"), return_new = TRUE) cb #> [1] "Text\nfor\nclipboard" cb <- write_clip(c("Text", "for", "clipboard"), breaks = ", ", return_new = TRUE) cb #> [1] "Text, for, clipboard" ``` `write_clip` also tries to intelligently handle data.frames and matrices, rendering them with `write.table` so that they can be pasted into a spreadsheet like Excel. ``` r tbl <- data.frame(a = c(1, 2, 3), b = c(4, 5, 6)) cb <- write_clip(tbl, return_new = TRUE) cb #> [1] "a\tb\n1\t4\n2\t5\n3\t6" ``` `read_clip_tbl` will try to parse clipboard contents from spreadsheets into data frames directly. ## Developing with clipr See the “Developing with clipr” vignette included with this package for advisories on writing code that calls clipr functions. ## Nice uses of clipr (a non-comprehensive list) 1. [reprex](https://github.com/tidyverse/reprex) by [@jennybc](https://github.com/jennybc) takes R code on the clipboard and renders a reproducible example from it, ready to then paste on to GitHub, Stack Overflow, or the like. 2. [datapasta](https://github.com/milesmcbain/datapasta) by [@milesmcbain](https://github.com/milesmcbain) eases the copying and pasting of R objects in and out of different sources (Excel, Google Sheets). ------------------------------------------------------------------------ [Matthew Lincoln](https://matthewlincoln.net) clipr/build/0000755000176200001440000000000015204754130012463 5ustar liggesusersclipr/build/vignette.rds0000644000176200001440000000033215204754130015020 0ustar liggesusersb```b`aeb`b2 1# 'LI-K/K-,M,( MAS(WRVH i%9h*q t0XD90!icKM-F3% 5/$~hZ8S+`zP԰Aհe ,s\ܠL t7`~΢r=xA$Gs=ʕXVr78Fclipr/man/0000755000176200001440000000000015204664772012153 5ustar liggesusersclipr/man/clear_clip.Rd0000644000176200001440000000056714177762460014550 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/clipboard.R \name{clear_clip} \alias{clear_clip} \title{Clear clipboard} \usage{ clear_clip(...) } \arguments{ \item{\ldots}{Pass other options to \code{\link[=write_clip]{write_clip()}}.} } \description{ Clear the system clipboard. } \note{ This is a wrapper function for \code{write_clip("")} } clipr/man/read_clip_tbl.Rd0000644000176200001440000000232015204670675015221 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/read_clip_tbl.R \name{read_clip_tbl} \alias{read_clip_tbl} \title{Transforms output of \code{\link[=read_clip]{read_clip()}} into data frame.} \usage{ read_clip_tbl(x = read_clip(), ...) } \arguments{ \item{x}{Defaults to reading from the clipboard, but can be substituted by a character vector already generated by \code{\link[=read_clip]{read_clip()}}.} \item{\ldots}{Options to pass to \code{\link[=read.table]{read.table()}}. The following \code{\link[=read.table]{read.table()}} arguments will be passed by default, but can be overridden by specifying them when calling \code{read_clip_tbl}: \describe{ \item{\code{header}}{\code{TRUE}} \item{\code{sep}}{\code{"\\t"}} \item{\code{row.names}}{\code{1}} \item{\code{stringsAsFactors}}{\code{FALSE}} \item{\code{na.strings}}{\code{c("NA", "")}} \item{\code{strip.white}}{\code{TRUE}} \item{\code{quote}}{\code{""}} }} } \value{ A data frame with the contents of the clipboard. If the system clipboard is empty, returns \code{NULL} } \description{ Transforms clipped content into a data frame by putting \code{\link[=read_clip]{read_clip()}} output by using \code{\link[=read.table]{read.table()}}. } clipr/man/read_clip.Rd0000644000176200001440000000157714177762460014377 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/clipboard.R \name{read_clip} \alias{read_clip} \title{Read clipboard} \usage{ read_clip(allow_non_interactive = Sys.getenv("CLIPR_ALLOW", interactive())) } \arguments{ \item{allow_non_interactive}{By default, clipr will throw an error if run in a non-interactive session. Set the environment variable \code{CLIPR_ALLOW=TRUE} in order to override this behavior.} } \value{ A character vector with the contents of the clipboard. If the system clipboard is empty, returns NULL } \description{ Read the contents of the system clipboard into a character vector. } \note{ \code{\link[=read_clip]{read_clip()}} will not try to guess at how to parse copied text. If you are copying tabular data, it is suggested that you use \code{\link[=read_clip_tbl]{read_clip_tbl()}}. } \examples{ \dontrun{ clip_text <- read_clip() } } clipr/man/clipr-package.Rd0000644000176200001440000000146615204664772015153 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/clipr-package.R \docType{package} \name{clipr-package} \alias{clipr-package} \title{clipr: Read and Write from the System Clipboard} \description{ Simple utility functions to read from and write to the Windows, OS X, and X11 clipboards. } \seealso{ Useful links: \itemize{ \item \url{https://github.com/mdlincoln/clipr} \item \url{http://matthewlincoln.net/clipr/} \item Report bugs at \url{https://github.com/mdlincoln/clipr/issues} } } \author{ \strong{Maintainer}: Matthew Lincoln \email{matthew.d.lincoln@gmail.com} (\href{https://orcid.org/0000-0002-4387-3384}{ORCID}) Other contributors: \itemize{ \item Louis Maddox [contributor] \item Steve Simpson [contributor] \item Jennifer Bryan [contributor] } } \keyword{internal} clipr/man/write_last_clip.Rd0000644000176200001440000000072514177762460015633 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/clipboard.R \name{write_last_clip} \alias{write_last_clip} \title{Write contents of the last R expression to the clipboard} \usage{ write_last_clip(...) } \arguments{ \item{\ldots}{Pass other options to \code{\link[=write_clip]{write_clip()}}.} } \description{ Write contents of the last R expression to the clipboard } \note{ This is a wrapper function for \code{write_clip(.Last.value)} } clipr/man/clipr_available.Rd0000644000176200001440000000261714177762460015562 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{clipr_available} \alias{clipr_available} \alias{dr_clipr} \title{Is the system clipboard available?} \usage{ clipr_available(...) dr_clipr(...) } \arguments{ \item{\ldots}{Pass other options to \code{\link[=write_clip]{write_clip()}}. Generally only used to pass the argument \code{allow_non_interactive_use = TRUE}.} } \value{ \code{clipr_available} returns a boolean value. Prints an informative message to the console with software and system configuration requirements if clipr is not available (invisibly returns the same string) } \description{ Checks to see if the system clipboard is write-able/read-able. This may be useful if you are developing a package that relies on clipr and need to ensure that it will skip tests on machines (e.g. CRAN, Travis) where the system clipboard may not be available. } \note{ This will automatically return \code{FALSE}, without even performing the check, if you are running in a non-interactive session. If you must call this non-interactively, be sure to call using \code{clipr_available(allow_non_interactive = TRUE)}, or by setting the environment variable \code{CLIPR_ALLOW=TRUE}. \strong{Do not attempt to run clipr non-interactively on CRAN; this will result in a failed build!} } \examples{ \dontrun{ # When using testthat: library(testthat) skip_if_not(clipr_available()) } } clipr/man/write_clip.Rd0000644000176200001440000000657215204670675014614 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/clipboard.R \name{write_clip} \alias{write_clip} \title{Write clipboard} \usage{ write_clip( content, object_type = c("auto", "character", "table"), breaks = NULL, eos = NULL, return_new = FALSE, allow_non_interactive = Sys.getenv("CLIPR_ALLOW", interactive()), ... ) } \arguments{ \item{content}{An object to be written to the system clipboard.} \item{object_type}{\code{\link[=write_clip]{write_clip()}} tries to be smart about writing objects in a useful manner. If passed a data.frame or matrix, it will format it using \code{\link[=write.table]{write.table()}} for pasting into an external spreadsheet program. It will otherwise coerce the object to a character vector. \code{auto} will check the object type, otherwise \code{table} or \code{character} can be explicitly specified.} \item{breaks}{The separator to be used between each element of the character vector being written. \code{NULL} defaults to writing system-specific line breaks between each element of a character vector, or each row of a table.} \item{eos}{The terminator to be written after each string, followed by an ASCII \code{nul}. Defaults to no terminator character, indicated by \code{NULL}.} \item{return_new}{If true, returns the rendered string; if false, returns the original object} \item{allow_non_interactive}{By default, clipr will throw an error if run in a non-interactive session. Set the environment variable \code{CLIPR_ALLOW=TRUE} in order to override this behavior.} \item{...}{Custom options to be passed to \code{\link[=write.table]{write.table()}} (if \code{x} is a table-like). Defaults to sane line-break and tab standards based on the operating system. By default, this will use \code{col.names = TRUE} if the table object has column names, and \code{row.names = TRUE} if the object has row names other than \verb{c("1", "2", "3"...)}. Override these defaults by passing arguments here.} } \value{ Invisibly returns the original object } \description{ Write a character vector to the system clipboard } \note{ On X11 systems, \code{\link[=write_clip]{write_clip()}} will cause either xclip (preferred) or xsel to be called. Be aware that, by design, these processes will fork into the background. They will run until the next paste event, when they will then exit silently. (See the man pages for \href{https://linux.die.net/man/1/xclip}{xclip} and \href{https://www.vergenet.net/~conrad/software/xsel/xsel.1x.html#notes}{xsel} for more on their behaviors.) However, this means that even if you terminate your R session after running \code{\link[=write_clip]{write_clip()}}, those processes will continue until you access the clipboard via another program. This may be expected behavior for interactive use, but is generally undesirable for non-interactive use. For this reason you must not run \code{\link[=write_clip]{write_clip()}} on CRAN, as the nature of xsel \href{https://github.com/mdlincoln/clipr/issues/38}{has caused issues in the past}. Call \code{\link[=clipr_available]{clipr_available()}} to safely check whether the clipboard is readable and writable. } \examples{ \dontrun{ text <- "Write to clipboard" write_clip(text) multiline <- c("Write", "to", "clipboard") write_clip(multiline) # Write # to # clipboard write_clip(multiline, breaks = ",") # write,to,clipboard tbl <- data.frame(a=c(1,2,3), b=c(4,5,6)) write_clip(tbl) } } clipr/man/clipr.Rd0000644000176200001440000000134515204664772013556 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/clipr-package.R \name{clipr} \alias{clipr} \title{clipr: Read and Write from the System Clipboard} \description{ Simple utility functions to read from and write to the Windows, OS X, and X11 clipboards. } \details{ The basic functions \code{\link[=read_clip]{read_clip()}} and \code{\link[=write_clip]{write_clip()}} wrap platform-specific functions for writing values from R to the system clipboard. \code{\link[=read_clip_tbl]{read_clip_tbl()}} will attempt to process the clipboard content like a table copied from a spreadsheet program. \code{\link[=clipr_available]{clipr_available()}} is useful when building packages that depend on clipr functionality. } clipr/DESCRIPTION0000644000176200001440000000262615204761412013101 0ustar liggesusersType: Package Package: clipr Title: Read and Write from the System Clipboard Version: 0.8.1 Authors@R: c( person("Matthew", "Lincoln", , "matthew.d.lincoln@gmail.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-4387-3384")), person("Louis", "Maddox", role = "ctb"), person("Steve", "Simpson", role = "ctb"), person("Jennifer", "Bryan", role = "ctb") ) Description: Simple utility functions to read from and write to the Windows, OS X, and X11 clipboards. License: GPL-3 URL: https://github.com/mdlincoln/clipr, http://matthewlincoln.net/clipr/ BugReports: https://github.com/mdlincoln/clipr/issues Imports: utils Suggests: covr, knitr, rmarkdown, rstudioapi (>= 0.5), testthat (>= 2.0.0) VignetteBuilder: knitr Encoding: UTF-8 Language: en-US RoxygenNote: 7.3.3 SystemRequirements: xclip (https://github.com/astrand/xclip) or xsel (http://www.vergenet.net/~conrad/software/xsel/) for accessing the X11 clipboard, or wl-clipboard (https://github.com/bugaevc/wl-clipboard) for systems using Wayland. NeedsCompilation: no Packaged: 2026-05-25 05:04:26 UTC; mlincoln Author: Matthew Lincoln [aut, cre] (ORCID: ), Louis Maddox [ctb], Steve Simpson [ctb], Jennifer Bryan [ctb] Maintainer: Matthew Lincoln Repository: CRAN Date/Publication: 2026-05-25 05:50:02 UTC