Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]

name: R-CMD-check

jobs:
R-CMD-check:
runs-on: ${{ matrix.config.os }}

name: ${{ matrix.config.os }} (${{ matrix.config.r }})

strategy:
fail-fast: false
matrix:
config:
- {os: ubuntu-latest, r: 'release'}

env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
R_KEEP_PKG_SOURCE: yes

steps:
- uses: actions/checkout@v4

- uses: r-lib/actions/setup-pandoc@v2

- uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
use-public-rspm: true

- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::rcmdcheck
needs: check

- uses: r-lib/actions/check-r-package@v2
with:
upload-snapshots: true
args: 'c("--no-manual", "--as-cran", "--no-vignettes")'
build_args: 'c("--no-manual", "--no-build-vignettes")'
error-on: '"error"'
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ Suggests:
Encoding: UTF-8
Language: en-US
LazyData: true
RoxygenNote: 7.1.0
RoxygenNote: 7.3.3
VignetteBuilder: knitr
11 changes: 11 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@

export(align_arrow)
export(align_equal)
export(align_pipe)
export(align_pipe_text)
export(align_text)
export(align_tilde)
export(backtickr)
export(blockquoter)
export(boldr)
export(br_r)
export(chunknamer)
export(chunkr)
export(chunksplitr)
export(cite_packages)
export(default_hotkeys)
export(entire_document)
export(footnoter)
export(h1r)
Expand All @@ -16,6 +23,7 @@ export(h3r)
export(h4r)
export(h5r)
export(h6r)
export(headr_toggler)
export(htmlcommentr)
export(id_ref)
export(imager)
Expand All @@ -25,14 +33,17 @@ export(italicsr)
export(latexr)
export(listr)
export(olistr)
export(packages_in_text)
export(remedy_example)
export(remedy_opts)
export(remedy_opts_current)
export(rename_chunks)
export(rightr)
export(scratch_file)
export(set_text)
export(striker)
export(tabler)
export(toggle_header)
export(urlr)
export(xaringanr)
export(youtuber)
Expand Down
19 changes: 19 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# remedy 0.1.0.9000

* `chunknamer()` no longer mangles non-R engine chunks such as `stan`, `python`,
`sql` or `bash` (#57). Text transformation is now exposed as the pure helper
`rename_chunks()` for easier testing.
* `chunknamer()` / `rename_chunks()` accept `remedy_opts$set(name = "")` to
disable auto-naming (#73).
* New `align_tilde()` addin aligns `~` in a highlighted region (#67).
* New `align_pipe()` addin aligns `|` columns in a markdown table (#58),
backed by the pure helper `align_pipe_text()`.
* New helper `align_text()` factored out from the `align_*` addins.
* New `default_hotkeys()` helper builds the default hotkey map; on
Windows / Linux `Cmd` is rewritten to `Ctrl` so the defaults are usable
cross-platform (#70). Shortcuts for `align_arrow`, `align_equal`,
`align_tilde`, `align_pipe` and `br` are included by default (#29, #60).
* New `br_r()` addin inserts a `<br>` line break at the cursor (#60).
* New `headr_toggler()` addin and `toggle_header()` helper cycle the header
level of the current line (#59).
* New `cite_packages()` helper returns a bulleted markdown list of the
citations for packages referenced in the current document (#20). The
discovery helper `packages_in_text()` is also exported.
* Clean pkgdown on github
* Added travis support and codecov.

Expand Down
200 changes: 160 additions & 40 deletions R/align.R
Original file line number Diff line number Diff line change
@@ -1,39 +1,32 @@
## Currently taken verbatim from
## https://github.com/seasmith/AlignAssign/blob/b32a2f0847a7818c9768a105cf2d891db0b0ee8d/R/align_assign.R
## as of 11-Nov-2016
## since AlignAssign is not on CRAN and CRAN packages can't have Remotes dependencies
## J. Carroll: I have updated the roxygen tags but otherwise this is as-per that commit
## Core alignment primitives were originally taken from
## https://github.com/seasmith/AlignAssign (see also #67, #58)

capture <- function() {
# Get context
rstudioapi::getActiveDocumentContext()
}

capture_area <- function(capture) {
# Find range
range_start <- capture$selection[[1L]]$range$start[[1L]]
range_end <- capture$selection[[1L]]$range$end[[1L]]

# Dump contents and use highlighted lines as names.

contents <- capture$contents[range_start:range_end]
names(contents) <- range_start:range_end
return(contents)
}

find_regex <- function(find, where) {

# Find matches, extract positions, find furthest <-, get rows/cols to align.

matched.rows <- grep(find, where)
positions <- regexec(find, where)
positions <- positions[matched.rows]

lines.highlighted <- as.integer(names(where))
matched.cols <- sapply(positions, `[[`, 1L)
which.max.col <- which.max(matched.cols)

furthest_row <- lines.highlighted[matched.rows[which.max.col]]
furthest_column <- max(matched.cols)

return(list(matched.rows = matched.rows,
matched.cols = matched.cols,
lines.highlighted = lines.highlighted,
Expand All @@ -42,73 +35,200 @@ find_regex <- function(find, where) {
}

assemble_insert <-function(info) {
# Unload variables
matched.rows <- info$matched.rows
matched.cols <- info$matched.cols
lines.highlighted <- info$lines.highlighted
which.max.col <- info$which.max.col
furthest_column <- info$furthest_column

# Find the rows to align and the current column position of each regEx match.

rows_to_align <- lines.highlighted[matched.rows[-which.max.col]]
columns_to_align <- matched.cols[-which.max.col]

# Set location for spaces to be inserted.

location <- Map(c, rows_to_align, columns_to_align)

# Find and set the number of spaces to insert on each line.

text_num <- furthest_column - columns_to_align
text <- vapply(text_num,
function(x) paste0(rep(" ", x), collapse = ""),
character(1))

return(list(location = location, text = text))
}

insertr <- function(list) {
rstudioapi::insertText(list[["location"]], list[["text"]])
}

#' Pad a character vector so the first occurrence of `find` lines up
#'
#' Pure helper shared by the `align_*` addins. Adds spaces before the
#' first match of `find` on each line so the matches sit at the same column.
#' Lines without a match are left untouched.
#'
#' @param lines character vector of lines.
#' @param find character(1), a regular expression (unless `fixed = TRUE`).
#' @param fixed logical, passed to `regexpr`.
#'
#' @return a character vector the same length as `lines`.
#' @keywords internal
#' @export
align_text <- function(lines, find, fixed = TRUE) {
positions <- as.integer(regexpr(find, lines, fixed = fixed))
hits <- positions > 0
if (sum(hits) < 2L) return(lines)
target <- max(positions[hits])
to_pad <- which(hits & positions < target)
for (i in to_pad) {
n <- target - positions[i]
lines[i] <- paste0(
substr(lines[i], 1L, positions[i] - 1L),
strrep(" ", n),
substr(lines[i], positions[i], nchar(lines[i]))
)
}
lines
}

#' Align pipe (`|`) columns in a markdown table
#'
#' Pure helper used by [align_pipe()]. Each line that contains a `|` is
#' treated as a table row; cells are right-padded so the `|` separators
#' line up across rows. Non-pipe lines pass through untouched.
#'
#' @param lines character vector of lines.
#'
#' @return a character vector the same length as `lines`.
#' @keywords internal
#' @export
align_pipe_text <- function(lines) {
has_pipe <- grepl("|", lines, fixed = TRUE)
if (!any(has_pipe)) return(lines)

idx <- which(has_pipe)
cells <- lapply(lines[idx], function(line) {
parts <- strsplit(line, "|", fixed = TRUE)[[1L]]
# strsplit drops trailing empty fields; preserve the closing `|`.
if (endsWith(line, "|")) parts <- c(parts, "")
parts
})
n_cols <- max(lengths(cells))
cells <- lapply(cells, function(r) {
if (length(r) < n_cols) c(r, rep("", n_cols - length(r))) else r
})

widths <- do.call(pmax, lapply(cells, nchar))

for (i in seq_along(cells)) {
row <- cells[[i]]
padded <- mapply(function(cell, w) {
if (nchar(cell) < w) paste0(cell, strrep(" ", w - nchar(cell))) else cell
}, row, widths, SIMPLIFY = TRUE, USE.NAMES = FALSE)
lines[idx[i]] <- paste(padded, collapse = "|")
}
lines
}

## Internal: rewrite the highlighted region in-place via align_text().
align_addin <- function(find, fixed = TRUE) {
adc <- rstudioapi::getActiveDocumentContext()
sel <- adc$selection[[1L]]$range
start_row <- sel$start[[1L]]
end_row <- sel$end[[1L]]

lines <- adc$contents[start_row:end_row]
aligned <- align_text(lines, find = find, fixed = fixed)

rng <- rstudioapi::document_range(
start = rstudioapi::document_position(start_row, 1L),
end = rstudioapi::document_position(end_row,
nchar(lines[length(lines)]) + 1L)
)
rstudioapi::modifyRange(rng, paste(aligned, collapse = "\n"), id = adc$id)
invisible(NULL)
}

#' Align a highlighted region's assignment operators.
#'
#' @return Aligns the single assignment operators (\code{<-}) within a highlighted region.
#' @export
#'
#' @examples
#'
#' @examples
#' \dontrun{
#' remedy_example(
#' c( "# Align arrows",
#' "a <- 12",
#' "aaa <- 13"),
#' "a <- 12",
#' "aaa <- 13"),
#' align_arrow
#' )
#' }
align_arrow <- function() {
capture <- capture()
area <- capture_area(capture)
loc <- find_regex("<-", area)
insertList <- assemble_insert(loc)
insertr(insertList)
align_addin("<-")
}

#' Align a highlighted region's assignment operators.
#'
#' @return Aligns the equal sign assignment operators (\code{=}) within a
#' highlighted region.
#' @export
#' @examples
#' @examples
#' \dontrun{
#' remedy_example(
#' c( "# Align equal signs",
#' "a = 12",
#' "aaa = 13"),
#' "a = 12",
#' "aaa = 13"),
#' align_equal
#' )
#' }
align_equal <- function() {
capture <- capture()
area <- capture_area(capture)
loc <- find_regex("=", area)
insertList <- assemble_insert(loc)
insertr(insertList)
}
align_addin("=")
}

#' Align a highlighted region's tildes (`~`)
#'
#' Useful e.g. for the right-hand side of `case_when()` branches.
#'
#' @return Aligns the first `~` on each highlighted line.
#' @export
#' @examples
#' \dontrun{
#' remedy_example(
#' c( "# Align tildes",
#' "a ~ 12",
#' "aaa ~ 13"),
#' align_tilde
#' )
#' }
align_tilde <- function() {
align_addin("~")
}

#' Align `|` columns in a markdown table
#'
#' Pads cells in a highlighted markdown table so the `|` separators line up.
#'
#' @return Modifies the selected region in-place in the RStudio editor.
#' @export
#' @examples
#' \dontrun{
#' remedy_example(
#' c(
#' "|a|bb|ccc|",
#' "|1|2|3|"
#' ),
#' align_pipe
#' )
#' }
align_pipe <- function() {
adc <- rstudioapi::getActiveDocumentContext()
sel <- adc$selection[[1L]]$range
start_row <- sel$start[[1L]]
end_row <- sel$end[[1L]]

lines <- adc$contents[start_row:end_row]
aligned <- align_pipe_text(lines)

rng <- rstudioapi::document_range(
start = rstudioapi::document_position(start_row, 1L),
end = rstudioapi::document_position(end_row, nchar(lines[length(lines)]) + 1L)
)
rstudioapi::modifyRange(rng, paste(aligned, collapse = "\n"), id = adc$id)
}
Loading
Loading