clipr/0000755000176200001440000000000013515512123011361 5ustar liggesusersclipr/NAMESPACE0000644000176200001440000000027513515102363012605 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/README.md0000644000176200001440000000552113514631525012652 0ustar liggesusers # clipr [![CRAN status.](http://www.r-pkg.org/badges/version/clipr)](http://www.r-pkg.org/pkg/clipr) ![Downloads, grand total](http://cranlogs.r-pkg.org/badges/grand-total/clipr) [![Travis-CI Build Status](https://travis-ci.org/mdlincoln/clipr.svg?branch=master)](https://travis-ci.org/mdlincoln/clipr) [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/mdlincoln/clipr?branch=master&svg=true)](https://ci.appveyor.com/project/mdlincoln/clipr) [![Coverage Status](https://img.shields.io/codecov/c/github/mdlincoln/clipr/master.svg)](https://codecov.io/github/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 devtools::install_github("mdlincoln/clipr") ``` ## Usage ``` r library("clipr") #> Welcome to clipr. See ?write_clip for advisories on writing to the clipboard in R. cb <- read_clip() ``` clipr is pipe-friendly, and will default to returning the same object that was passed in. ``` r res <- write_clip(c("Text", "for", "clipboard")) res #> [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/jennybc/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](http://matthewlincoln.net) clipr/man/0000755000176200001440000000000013515067466012153 5ustar liggesusersclipr/man/clipr_available.Rd0000644000176200001440000000261713515067466015561 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/clipr.Rd0000644000176200001440000000141513514631525013544 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/clipr-package.R \docType{package} \name{clipr} \alias{clipr} \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. } \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/man/write_clip.Rd0000644000176200001440000000655513515067466014616 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 \code{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{http://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/clear_clip.Rd0000644000176200001440000000056713514631525014537 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.Rd0000644000176200001440000000160113515067466014362 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/write_last_clip.Rd0000644000176200001440000000072513514631525015622 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/read_clip_tbl.Rd0000644000176200001440000000226013514631525015215 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}} }} } \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/DESCRIPTION0000644000176200001440000000271313515512123013072 0ustar liggesusersType: Package Package: clipr Title: Read and Write from the System Clipboard Version: 0.7.0 Authors@R: c(person(given = "Matthew", family = "Lincoln", role = c("aut", "cre"), email = "matthew.d.lincoln@gmail.com", comment = c(ORCID = "0000-0002-4387-3384")), person(given = "Louis", family = "Maddox", role = "ctb"), person(given = "Steve", family = "Simpson", role = "ctb"), person(given = "Jennifer", family = "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 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 LazyData: TRUE RoxygenNote: 6.1.1 SystemRequirements: xclip (https://github.com/astrand/xclip) or xsel (http://www.vergenet.net/~conrad/software/xsel/) for accessing the X11 clipboard NeedsCompilation: no Packaged: 2019-07-23 02:33:48 UTC; admin Author: Matthew Lincoln [aut, cre] (), Louis Maddox [ctb], Steve Simpson [ctb], Jennifer Bryan [ctb] Maintainer: Matthew Lincoln Repository: CRAN Date/Publication: 2019-07-23 05:00:03 UTC clipr/build/0000755000176200001440000000000013515471013012462 5ustar liggesusersclipr/build/vignette.rds0000644000176200001440000000033113515471013015016 0ustar liggesusersb```b`f@&0rHKdgd&d妠)u+T)T+DS$ݴ48U X%Z]?4-ީE0=(jؠjX2sRad9.nP&c0Gq?gQ~iݣ9JI,IK+ʴclipr/tests/0000755000176200001440000000000013012152157012522 5ustar liggesusersclipr/tests/testthat/0000755000176200001440000000000013515512123014363 5ustar liggesusersclipr/tests/testthat/test-diagnostics.R0000644000176200001440000000360713515067466020017 0ustar liggesuserscontext("diagnostics") test_that("clipr_available fails when DISPLAY is not configured; succeeds when it is", { # Only run this test on Travis skip_if_not(identical(Sys.getenv("TRAVIS"), "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("TRAVIS_CLIP"), "none")) expect_false(is_clipr_available) if (identical(Sys.getenv("TRAVIS_CLIP"), "xclip")) expect_true(is_clipr_available) if (identical(Sys.getenv("TRAVIS_CLIP"), "xsel")) 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("TRAVIS_CLIP"), "xclip")) expect_message(dr_clipr(), msg_clipr_available(), fixed = TRUE) if (identical(Sys.getenv("TRAVIS_CLIP"), "xsel")) expect_message(dr_clipr(), msg_clipr_available(), fixed = TRUE) if (identical(Sys.getenv("TRAVIS_CLIP"), "none")) expect_message(dr_clipr(), msg_no_clipboard(), fixed = TRUE) if (identical(Sys.getenv("TRAVIS_CLIP"), "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.R0000644000176200001440000000027613416120332015650 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/test_render.R0000644000176200001440000001304013514631525017031 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("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.R0000644000176200001440000000104713415746073017210 0ustar liggesuserscontext("systems") test_that("utility checking works on Linux-like", { if (identical(Sys.getenv("TRAVIS_CLIP"), "xclip")) { expect_true(has_xclip()) expect_false(has_xsel()) } if (identical(Sys.getenv("TRAVIS_CLIP"), "xsel")) { expect_false(has_xclip()) expect_true(has_xsel()) } if (identical(Sys.getenv("TRAVIS_CLIP"), "none")) { expect_false(has_xclip()) expect_false(has_xsel()) } if (identical(Sys.getenv("TRAVIS_CLIP"), "nodisplay")) { expect_error(has_xclip()) expect_false(has_xsel()) } }) clipr/tests/testthat.R0000644000176200001440000000006613012152157014507 0ustar liggesuserslibrary(testthat) library(clipr) test_check("clipr") clipr/vignettes/0000755000176200001440000000000013515471014013374 5ustar liggesusersclipr/vignettes/developing-with-clipr.Rmd0000644000176200001440000000625213515067461020270 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 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 [Travis.ci](https://travis-ci.org/) to check your package build on Linux, consult the [`.travis.yml`](https://github.com/mdlincoln/clipr/blob/master/.travis.yml) 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. ## 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/R/0000755000176200001440000000000013515073031011562 5ustar liggesusersclipr/R/win_clipboard.R0000644000176200001440000000154313012227712014523 0ustar liggesusers# Helper function to read from the Windows clipboard win_read_clip <- function() { utils::readClipboard() } # Helper function to write to the Windows clipboard win_write_clip <- function(content, object_type, breaks, eos, return_new, ...) { .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 = 1) if (return_new) { rendered_content } else { content } } clipr/R/utils.R0000644000176200001440000000615413515073031013053 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'." 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/R/flat_str.R0000644000176200001440000000416313514631525013536 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/clipboard.R0000644000176200001440000001253113515073031013646 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](http://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/linux_clipboard.R0000644000176200001440000000507013163753300015070 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 = TRUE), error = function(c) FALSE, warning = function(c) 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")) # 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'. 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") } 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'. 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 -b -i", "w") } else { notify_no_cb() } .dots <- list(...) write_nix(content, object_type, breaks, eos, return_new, con, .dots) } clipr/R/read_clip_tbl.R0000644000176200001440000000276213514631525014506 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`} } #' #' @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(x, collapse = "\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 do.call(utils::read.table, args = .dots) } clipr/R/osx_clipboard.R0000644000176200001440000000321613033775672014556 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.R0000644000176200001440000000056413012244176014164 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/clipr-package.R0000644000176200001440000000105313514631525014415 0ustar liggesusers#' 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. #' #' @docType package #' @name clipr NULL clipr/NEWS.md0000644000176200001440000001140613515470717012475 0ustar liggesusers## 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/MD50000644000176200001440000000323013515512123011667 0ustar liggesusersb589d701a66d28b4abf01606c508f9ac *DESCRIPTION ac9216bb379e4dad41fcf47ac889c3d9 *NAMESPACE af9b75f50e56f7400f6d5f940a0e18fc *NEWS.md 203d99a65e5a8f20a339cad36becb76c *R/clipboard.R 9c75ab4e1359ffadc1c01d04b23b70e4 *R/clipr-package.R c3673645d26e307510e4b9092022ab7b *R/clipr_addin.R 78462ea037dad6dc795301e220542f80 *R/flat_str.R a9d3a2d85d19d3c744e292a1d28d0beb *R/linux_clipboard.R 127954870f38794f4b2671fc08623ac6 *R/osx_clipboard.R 9f8d569f398395aafbe00886fca97306 *R/read_clip_tbl.R 2b79dade139d8e25adcb80676bde7053 *R/utils.R 3c7e982c589ee3323a86f5ebc6c41984 *R/win_clipboard.R 3f23a4ae45455f71def812024c1337de *README.md fea4c83a6f6c4e00d5e3b204fa1dcdb7 *build/vignette.rds bbc07ec72cddb8d28f1c2a7ab322f031 *inst/doc/developing-with-clipr.R a2ee2d9d5e2d92ab65107157675b472a *inst/doc/developing-with-clipr.Rmd 7ae52ced26d82ecfbb0d5d847fe1a62b *inst/doc/developing-with-clipr.html c5d91ccff2716bd64fd3dbf351507c07 *inst/rstudio/addins.dcf f8c1c7e8cb9612e9c3d58455491fba2b *man/clear_clip.Rd 8811fc710bb01c458907fde5e55550b8 *man/clipr.Rd 9ff95009c8aa71675ae5d2e6513d0e64 *man/clipr_available.Rd d6e7b166e4a79a0353059328852cae9d *man/read_clip.Rd 70361285201fc90000590a774a1f59e4 *man/read_clip_tbl.Rd 9f29a2a82f4c1b949f3c7af7e8ac8fd0 *man/write_clip.Rd 9ad848459b1749b5a5a26c74d9db944e *man/write_last_clip.Rd ec77100d776b5924e0da206268d2517d *tests/testthat.R 51d8d49a44ccf1bc6771a64ecc6a4d22 *tests/testthat/setup.R 256e2256c7b43620b97402800dfd24ef *tests/testthat/test-diagnostics.R ab5cfcd3a862fa5e868892bc938b009f *tests/testthat/test-systems.R c84adc3c418b98dd0b8be2db8c798452 *tests/testthat/test_render.R a2ee2d9d5e2d92ab65107157675b472a *vignettes/developing-with-clipr.Rmd clipr/inst/0000755000176200001440000000000013515471013012340 5ustar liggesusersclipr/inst/rstudio/0000755000176200001440000000000013012227632014027 5ustar liggesusersclipr/inst/rstudio/addins.dcf0000644000176200001440000000045713012234251015750 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/inst/doc/0000755000176200001440000000000013515471013013105 5ustar liggesusersclipr/inst/doc/developing-with-clipr.R0000644000176200001440000000021213515471013017437 0ustar liggesusers## ----setup, include = FALSE---------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) clipr/inst/doc/developing-with-clipr.Rmd0000644000176200001440000000625213515067461020002 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 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 [Travis.ci](https://travis-ci.org/) to check your package build on Linux, consult the [`.travis.yml`](https://github.com/mdlincoln/clipr/blob/master/.travis.yml) 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. ## 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.html0000644000176200001440000001706113515471013020214 0ustar liggesusers Developing with clipr

Developing with clipr

Matthew Lincoln

2019-07-22

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 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 Travis.ci to check your package build on Linux, consult the .travis.yml 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.

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.