Nothing
#' Delete cells
#'
#' Deletes a range of cells and shifts other cells into the deleted area. There
#' are several related tasks that are implemented by other functions:
#' * To clear cells of their value and/or format, use [range_clear()].
#' * To delete an entire (work)sheet, use [sheet_delete()].
#' * To change the dimensions of a (work)sheet, use [sheet_resize()].
#'
#' @eval param_ss()
#' @eval param_sheet(
#' action = "delete",
#' "Ignored if the sheet is specified via `range`. If neither argument",
#' "specifies the sheet, defaults to the first visible sheet."
#' )
#' @param range Cells to delete. There are a couple differences between `range`
#' here and how it works in other functions (e.g. [range_read()]):
#' * `range` must be specified.
#' * `range` must not be a named range.
#' * `range` must not be the name of a (work) sheet. Instead, use
#' [sheet_delete()] to delete an entire sheet.
#' Row-only and column-only ranges are especially relevant, such as "2:6" or
#' "D". Remember you can also use the helpers in [`cell-specification`],
#' such as `cell_cols(4:6)`, or `cell_rows(5)`.
#' @param shift Must be one of "up" or "left", if specified. Required if `range`
#' is NOT a rows-only or column-only range (in which case, we can figure it
#' out for you). Determines whether the deleted area is filled by shifting
#' surrounding cells up or to the left.
#'
#' @template ss-return
#' @export
#' @family write functions
#' @seealso Makes a `DeleteRangeRequest`:
#' * <https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteRangeRequest>
#'
#' @examplesIf gs4_has_token()
#' # create a data frame to use as initial data
#' df <- gs4_fodder(10)
#'
#' # create Sheet
#' ss <- gs4_create("range-delete-example", sheets = list(df))
#'
#' # delete some rows
#' range_delete(ss, range = "2:4")
#'
#' # delete a column
#' range_delete(ss, range = "C")
#'
#' # delete a rectangle and specify how to shift remaining cells
#' range_delete(ss, range = "B3:F4", shift = "left")
#'
#' # clean up
#' gs4_find("range-delete-example") %>%
#' googledrive::drive_trash()
range_delete <- function(ss,
sheet = NULL,
range,
shift = NULL) {
ssid <- as_sheets_id(ss)
maybe_sheet(sheet)
check_range(range)
stopifnot(!is.null(range))
if (is.null(shift)) {
shift_dimension <- NULL
} else {
shift <- match.arg(shift, c("up", "left"))
shift_dimension <- switch(shift,
up = "ROWS",
left = "COLUMNS"
)
}
x <- gs4_get(ssid)
gs4_bullets(c(v = "Editing {.s_sheet {x$name}}."))
# determine (work)sheet and range --------------------------------------------
range_spec <- as_range_spec(
range,
sheet = sheet,
sheets_df = x$sheets, nr_df = x$named_ranges
)
if (is.null(range_spec$cell_range) && is.null(range_spec$cell_limits)) {
gs4_abort("{.fun range_delete} requires a cell range.")
}
range_spec$sheet_name <- range_spec$sheet_name %||% first_visible_name(x$sheets)
# as_GridRange() throws an error for a named range
grid_range <- as_GridRange(range_spec)
gs4_bullets(c(v = "Deleting cells in sheet {.w_sheet {range_spec$sheet_name}}."))
# form batch update request --------------------------------------------------
shift_dimension <- shift_dimension %||% determine_shift(grid_range)
if (is.null(shift_dimension)) {
gs4_abort(c(
"The {.arg shift} direction must be specified for this {.arg range}.",
"It can't be automatically determined."
))
}
# form batch update request --------------------------------------------------
delete_req <- list(deleteRange = new(
"DeleteRangeRequest",
range = grid_range,
shiftDimension = shift_dimension
))
# do it ----------------------------------------------------------------------
req <- request_generate(
"sheets.spreadsheets.batchUpdate",
params = list(
spreadsheetId = ssid,
requests = list(delete_req)
)
)
resp_raw <- request_make(req)
gargle::response_process(resp_raw)
invisible(ssid)
}
determine_shift <- function(gr, call = caller_env()) {
stopifnot(inherits(gr, "googlesheets4_schema_GridRange"))
bounded_on_bottom <- !is.null(gr$endRowIndex) && notNA(gr$endRowIndex)
bounded_on_right <- !is.null(gr$endColumnIndex) && notNA(gr$endColumnIndex)
if (bounded_on_bottom && bounded_on_right) { # user must specify shift
return(NULL)
}
if (bounded_on_bottom) { # and not bounded_on_right
return("ROWS")
}
if (bounded_on_right) { # and not bounded_on_bottom
return("COLUMNS")
}
gs4_abort(
c(
"{.arg range} must be bounded on the bottom and/or on the right.",
i = "Use {.fun sheet_delete} or {.fun sheet_resize} to delete or \\
resize a (work)sheet."
),
call = call
)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.