├── .Rbuildignore
├── .gitignore
├── .travis.yml
├── AlignAssign.Rproj
├── DESCRIPTION
├── NAMESPACE
├── R
├── .gitignore
└── align_assign.R
├── README.Rmd
├── README.md
├── inst
├── media
│ ├── Thumbs.db
│ ├── demo.gif
│ ├── demo2.gif
│ └── demo_cursors.gif
└── rstudio
│ └── addins.dcf
└── man
├── alignAssign.Rd
├── alignAssignArrow.Rd
└── alignAssignEqual.Rd
/.Rbuildignore:
--------------------------------------------------------------------------------
1 | ^.*\.Rproj$
2 | ^\.Rproj\.user$
3 | ^.travis.yml$
4 | ^R/findAndReplaceAddin\.R$
5 | ^R/ui\.R$
6 | ^R/tst\.R$
7 | ^R/utils\.R$
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .Rproj.user
2 | .Rhistory
3 | .RData
4 | .Ruserdata
5 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: r
2 | cache: packages
3 |
--------------------------------------------------------------------------------
/AlignAssign.Rproj:
--------------------------------------------------------------------------------
1 | Version: 1.0
2 |
3 | RestoreWorkspace: Default
4 | SaveWorkspace: Default
5 | AlwaysSaveHistory: Default
6 |
7 | EnableCodeIndexing: Yes
8 | UseSpacesForTab: Yes
9 | NumSpacesForTab: 2
10 | Encoding: UTF-8
11 |
12 | RnwWeave: Sweave
13 | LaTeX: pdfLaTeX
14 |
15 | AutoAppendNewline: Yes
16 | StripTrailingWhitespace: Yes
17 |
18 | BuildType: Package
19 | PackageUseDevtools: Yes
20 | PackageInstallArgs: --no-multiarch --with-keep.source
21 |
--------------------------------------------------------------------------------
/DESCRIPTION:
--------------------------------------------------------------------------------
1 | Package: AlignAssign
2 | Type: Package
3 | Title: Align the assignment operators within a highlighted area
4 | Version: 0.5.0
5 | Authors@R: c(
6 | person("Luke", "Smith", , "lukedansmi@sbcglobal.net", role = c("aut", "cre")),
7 | person("Garrick", "Aden-Buie", , role = "aut")
8 | )
9 | URL: https://github.com/seasmith/AlignAssign
10 | BugReports: https://github.com/seasmith/AlignAssign/issues
11 | Description: A very simple aligner for a highlighted region's '<-' or '='
12 | assignment operators. It does not "reflow" your code if the alignment
13 | breaks the page width. This addin also does not treat commented lines
14 | differently than uncommented lines.
15 | Imports:
16 | rstudioapi
17 | License: GPL-2
18 | Encoding: UTF-8
19 | LazyData: true
20 | RoxygenNote: 6.0.1
21 |
--------------------------------------------------------------------------------
/NAMESPACE:
--------------------------------------------------------------------------------
1 | # Generated by roxygen2: do not edit by hand
2 |
3 | export(alignAssign)
4 | export(alignAssignArrow)
5 | export(alignAssignEqual)
6 |
--------------------------------------------------------------------------------
/R/.gitignore:
--------------------------------------------------------------------------------
1 | findAndReplaceAddin.R
2 | tst.r
3 | ui.R
4 | utils.R
5 |
--------------------------------------------------------------------------------
/R/align_assign.R:
--------------------------------------------------------------------------------
1 | capture <- function() {
2 | # Get context
3 | rstudioapi::getActiveDocumentContext()
4 | }
5 |
6 | captureArea <- function(capture) {
7 | # Find range
8 | range_start <- capture$selection[[1L]]$range$start[[1L]]
9 | range_end <- capture$selection[[1L]]$range$end[[1L]]
10 |
11 | # Dump contents and use highlighted lines as names.
12 | contents <- capture$contents[range_start:range_end]
13 | names(contents) <- range_start:range_end
14 | return(contents)
15 | }
16 |
17 | findRegEx <- function(find, where) {
18 |
19 | # Find matches, extract positions, find furthest <-, get rows/cols to align.
20 | matched.rows <- grep(find, where)
21 | positions <- regexec(find, where)
22 | positions <- positions[matched.rows]
23 |
24 | lines.highlighted <- as.integer(names(where))
25 | matched.cols <- sapply(positions, `[[`, 1L)
26 | which.max.col <- which.max(matched.cols)
27 |
28 | furthest_row <- lines.highlighted[matched.rows[which.max.col]]
29 | furthest_column <- max(matched.cols)
30 |
31 | return(list(matched.rows = matched.rows,
32 | matched.cols = matched.cols,
33 | lines.highlighted = lines.highlighted,
34 | which.max.col = which.max.col,
35 | furthest_column = furthest_column))
36 | }
37 |
38 | assembleInsert <-function(info) {
39 | # Unload variables
40 | matched.rows <- info$matched.rows
41 | matched.cols <- info$matched.cols
42 | lines.highlighted <- info$lines.highlighted
43 | which.max.col <- info$which.max.col
44 | furthest_column <- info$furthest_column
45 |
46 | # Find the rows to align and the current column position of each regEx match.
47 | rows_to_align <- lines.highlighted[matched.rows[-which.max.col]]
48 | columns_to_align <- matched.cols[-which.max.col]
49 |
50 | # Set location for spaces to be inserted.
51 | location <- Map(c, rows_to_align, columns_to_align)
52 |
53 | # Find and set the number of spaces to insert on each line.
54 | text_num <- furthest_column - columns_to_align
55 | text <- vapply(text_num,
56 | function(x) paste0(rep(" ", x), collapse = ""),
57 | character(1))
58 |
59 | return(list(location = location, text = text))
60 | }
61 |
62 | insertr <- function(list) {
63 | rstudioapi::insertText(list[["location"]], list[["text"]])
64 | }
65 |
66 | #' Align a highlighted region's assignment operators.
67 | #'
68 | #' @param rgx_op Regex for assignment operator
69 | #' @return
70 | #' Aligns the given or guessed operator within a highlighted region.
71 | #' @export
72 | alignAssign <- function(rgx_op = NULL) {
73 | capture <- capture()
74 | area <- captureArea(capture)
75 | if (is.null(rgx_op)) rgx_op <- guess_operator(area)
76 | loc <- findRegEx(rgx_op, area)
77 | insertList <- assembleInsert(loc)
78 | insertr(insertList)
79 | }
80 |
81 | #' Align a highlighted region's assignment operators.
82 | #'
83 | #' @return Aligns the equal sign assignment operators (\code{=}) within a
84 | #' highlighted region.
85 | #' @export
86 | alignAssignEqual <- function() {
87 | alignAssign("=")
88 | }
89 |
90 | #' Align a highlighted region's assignment operators.
91 | #'
92 | #' @return Aligns the single caret operators (\code{<-}) within a
93 | #' highlighted region.
94 | #' @export
95 | alignAssignArrow <- function() {
96 | alignAssign("<-")
97 | }
98 |
99 | guess_operator <- function(area = captureArea(capture())) {
100 | area <- strsplit(area, "\n")
101 | counts <- list(
102 | "=" = vapply(gregexpr("=", area, fixed = TRUE), function(x) length(x[x > 0]), integer(1)),
103 | "<-" = vapply(gregexpr("<-", area, fixed = TRUE), function(x) length(x[x > 0]), integer(1))
104 | )
105 | # Does one appear in all? (keep)
106 | all_ones <- vapply(lapply(counts, function(x) x == 1), all, logical(1))
107 | if (sum(all_ones) == 1) return(names(all_ones)[all_ones])
108 |
109 | # Does only one appear at all? (keep)
110 | nones <- vapply(lapply(counts, function(x) x == 0), all, logical(1))
111 | if (sum(nones) == 1) {
112 | return(names(counts)[!nones])
113 | } else if (sum(nones) == 2) {
114 | stop("Neither `=` or `<-` are used in the selected lines")
115 | }
116 |
117 | # if not in all or none then are either duplicated on a line? (discard)
118 | mult_in_lines <- vapply(lapply(counts, function(x) x > 1), sum, integer(1))
119 | if (sum(mult_in_lines) == 1) return(names(counts)[!mult_in_lines])
120 |
121 | # fall back to max count
122 | some_ones <- vapply(lapply(counts, function(x) x == 1), sum, integer(1))
123 | all_same <- length(unique(counts)) == 1
124 | if (!all_same) {
125 | return(names(which.max(some_ones)))
126 | } else {
127 | warning("Couldn't guess the operator for alignment, trying ` <- `")
128 | return("<-")
129 | }
130 | }
131 |
132 | alignCursor <- function() {
133 | context <- rstudioapi::getActiveDocumentContext()
134 |
135 | cursors <- lapply(context$selection, function(x) {
136 | rbind(x$range$start, x$range$end)
137 | })
138 |
139 | if (length(cursors) < 2) {
140 | message("Nothing to align, did you place multiple cursors in the document?")
141 | return()
142 | }
143 |
144 | x <- as.data.frame(do.call("rbind", cursors))
145 | x <- unique(x)
146 | x <- x[order(x$row), ]
147 |
148 | # used to keep track of added space if multiple cursors per line
149 | added_spaces <- data.frame(row = unique(x$row), nt = 0L)
150 |
151 | x$group <- sequence(rle(x$row)$lengths)
152 | x <- split(x, x$group)
153 | for (xg in x) {
154 | xg <- merge(xg, added_spaces, by = "row")
155 | xg$column <- xg$column + xg$nt
156 | xg$n <- max(xg$column) - xg$column
157 | added_spaces <- update_spaces(added_spaces, xg)
158 | spaces_to_add <- make_space(xg$n)
159 | locs <- Map(c, xg$row, xg$column)
160 | rstudioapi::insertText(locs, spaces_to_add, id = context$id)
161 | }
162 | }
163 |
164 | make_space <- function(n) {
165 | vapply(n, function(nn) strrep(' ', nn), " ")
166 | }
167 |
168 | update_spaces <- function(a, x) {
169 | a <- merge(a, x[, c("row", "n")], by = "row")
170 | a$nt <- a$nt + x$n
171 | a[, c("row", "nt")]
172 | }
173 |
--------------------------------------------------------------------------------
/README.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | output: github_document
3 | ---
4 |
5 | # AlignAssign
6 |
7 | [](https://travis-ci.org/seasmith/AlignAssign)
8 |
9 | Align the assignment operators (either `<-` or `=`) within a highlighted area.
10 |
11 | Before:
12 | ```{r, eval=FALSE}
13 | a <- 1:5
14 | bbb <- 6:10
15 | c <- letters
16 | ```
17 |
18 | After:
19 | ```{r, eval=FALSE}
20 | a <- 1:5
21 | bbb <- 6:10
22 | c <- letters
23 | ```
24 |
25 | 
26 |
27 | #### Align Cursors
28 |
29 | For alignment of any text, you can align multiple cursors with the **Align Cursors** addin.
30 | Add multiple cursors to your document by holding Ctrl/Cmd + Alt and clicking in the RStudio editor, or by holding Alt and clicking and dragging the mouse.
31 |
32 | 
33 |
34 | ### What
35 | AlignAssign contains three addins. Two addins align all of either the `<-` (`Align Assign`) or `=` (`Align Assign 2`) assignment operators within a highlighted region and the third aligns multiple cursors across lines to the same column.
36 |
37 | None of the addins "reflow" your code if the alignment breaks the page width. They also does not treat commented lines differently to uncommented lines. __If there is either one of the assignment operators within a highlighted comment line, then it will either align that operator or align other operators to it.__
38 |
39 | ## Install
40 | ```{r install, eval=FALSE}
41 | devtools::install_github("seasmith/AlignAssign")`
42 | ```
43 |
44 | You can assign each alignment addin action to a specific keyboard shortcut in RStudio in the *Modify keyboard shortcuts...* menu option under the *Tools* menu.
45 |
46 | ## Examples
47 |
48 | #### Align `<-`'s with Align Assign
49 | When you highlight the following chunk of code (region) - whether you highlight the entirity or just a portion of the first and last lines - and then run the `Align Assign` addin...
50 | ```{r, eval=FALSE}
51 | # This is a commented line
52 | # So is this
53 | a <- 1:5
54 | b <- 6:10
55 | copy_a <- a
56 | # More comments
57 | ```
58 |
59 | ...the result will look like this.
60 | ```{r, eval=FALSE}
61 | # This is a commented line
62 | # So is this
63 | a <- 1:5
64 | b <- 6:10
65 | copy_a <- a
66 | # More comments
67 | ```
68 |
69 | #### Align `=`'s with Align Assign 2
70 | The above example also works for the `=` operator when using the other addin, `Align Assign 2`. Before...
71 | ```{r, eval=FALSE}
72 | # Perosnal information
73 | list(surname = "Crichton",
74 | firstName = "John",
75 | address = NA,
76 | occupation = "fugitive")
77 | ```
78 |
79 | ...after.
80 | ```{r, eval=FALSE}
81 | # Perosnal information
82 | list(surname = "Crichton",
83 | firstName = "John",
84 | address = NA,
85 | occupation = "fugitive")
86 | ```
87 |
88 | #### Behavior of commented-out assignment operators
89 | Be mindful that highling a chunk of code which has assignment operators within commented lines, like the following, and running the `Align Assign 2` addin...
90 | ```{r, eval=FALSE}
91 | # This is a commented line with an assignment operator <-
92 | a <- 1:5
93 | b <- 6:10
94 | c <- 11:15
95 | # There is an assignment operator <- here, too
96 | ```
97 |
98 | ...will result in something like this.
99 | ```{r, eval=FALSE}
100 | # This is a commented line with an assignment operator <-
101 | a <- 1:5
102 | b <- 6:10
103 | c <- 11:15
104 | # There is an assignment operator <- here, too
105 | ```
106 |
107 | #### Not so smart aligner
108 | There is also no special handling of assignment operators within a function. So, if you highlighted the entire chunk below and then ran the `Align Assign` addin...
109 | ```{r, eval=FALSE}
110 | var1 <- letters
111 | var2 <- as.list(sample(1:26, 26))
112 | names(var2) <- var1[unlist(var2)]
113 | list.pos <- function(name, lst){
114 | matches <- sapply(name, function(x){
115 | matched <- which(names(lst) %in% x)
116 |
117 | if(length(matched) == 0) matched <- NA
118 | matched
119 | })
120 | return(matches)
121 | }
122 | positions <- list.pos(c("a", "bbb", "c"), var2)
123 | ```
124 |
125 | ...the result will look like this.
126 | ```{r, eval=FALSE}
127 | var1 <- letters
128 | var2 <- as.list(sample(1:26, 26))
129 | names(var2) <- var1[unlist(var2)]
130 | list.pos <- function(name, lst){
131 | matches <- sapply(name, function(x){
132 | matched <- which(names(lst) %in% x)
133 |
134 | if(length(matched) == 0) matched <- NA
135 | matched
136 | })
137 | return(matches)
138 | }
139 | positions <- list.pos(c("a", "bbb", "c"), var2)
140 | ```
141 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # AlignAssign
3 |
4 | [](https://travis-ci.org/seasmith/AlignAssign)
6 |
7 | Align the assignment operators (either `<-` or `=`) within a highlighted
8 | area.
9 |
10 | Before:
11 |
12 | ``` r
13 | a <- 1:5
14 | bbb <- 6:10
15 | c <- letters
16 | ```
17 |
18 | After:
19 |
20 | ``` r
21 | a <- 1:5
22 | bbb <- 6:10
23 | c <- letters
24 | ```
25 |
26 | 
27 |
28 | #### Align Cursors
29 |
30 | For alignment of any text, you can align multiple cursors with the
31 | **Align Cursors** addin. Add multiple cursors to your document by
32 | holding Ctrl/Cmd + Alt and clicking in
33 | the RStudio editor, or by holding Alt and clicking and
34 | dragging the mouse.
35 |
36 | 
37 |
38 | ### What
39 |
40 | AlignAssign contains three addins. Two addins align all of either the
41 | `<-` (`Align Assign`) or `=` (`Align Assign 2`) assignment operators
42 | within a highlighted region and the third aligns multiple cursors across
43 | lines to the same column.
44 |
45 | None of the addins “reflow” your code if the alignment breaks the page
46 | width. They also does not treat commented lines differently to
47 | uncommented lines. **If there is either one of the assignment operators
48 | within a highlighted comment line, then it will either align that
49 | operator or align other operators to it.**
50 |
51 | ## Install
52 |
53 | ``` r
54 | devtools::install_github("seasmith/AlignAssign")`
55 | ```
56 |
57 | You can assign each alignment addin action to a specific keyboard
58 | shortcut in RStudio in the *Modify keyboard shortcuts…* menu option
59 | under the *Tools* menu.
60 |
61 | ## Examples
62 |
63 | #### Align `<-`’s with Align Assign
64 |
65 | When you highlight the following chunk of code (region) - whether you
66 | highlight the entirity or just a portion of the first and last lines -
67 | and then run the `Align Assign` addin…
68 |
69 | ``` r
70 | # This is a commented line
71 | # So is this
72 | a <- 1:5
73 | b <- 6:10
74 | copy_a <- a
75 | # More comments
76 | ```
77 |
78 | …the result will look like this.
79 |
80 | ``` r
81 | # This is a commented line
82 | # So is this
83 | a <- 1:5
84 | b <- 6:10
85 | copy_a <- a
86 | # More comments
87 | ```
88 |
89 | #### Align `=`’s with Align Assign 2
90 |
91 | The above example also works for the `=` operator when using the other
92 | addin, `Align Assign 2`. Before…
93 |
94 | ``` r
95 | # Perosnal information
96 | list(surname = "Crichton",
97 | firstName = "John",
98 | address = NA,
99 | occupation = "fugitive")
100 | ```
101 |
102 | …after.
103 |
104 | ``` r
105 | # Perosnal information
106 | list(surname = "Crichton",
107 | firstName = "John",
108 | address = NA,
109 | occupation = "fugitive")
110 | ```
111 |
112 | #### Behavior of commented-out assignment operators
113 |
114 | Be mindful that highling a chunk of code which has assignment operators
115 | within commented lines, like the following, and running the `Align
116 | Assign 2` addin…
117 |
118 | ``` r
119 | # This is a commented line with an assignment operator <-
120 | a <- 1:5
121 | b <- 6:10
122 | c <- 11:15
123 | # There is an assignment operator <- here, too
124 | ```
125 |
126 | …will result in something like this.
127 |
128 | ``` r
129 | # This is a commented line with an assignment operator <-
130 | a <- 1:5
131 | b <- 6:10
132 | c <- 11:15
133 | # There is an assignment operator <- here, too
134 | ```
135 |
136 | #### Not so smart aligner
137 |
138 | There is also no special handling of assignment operators within a
139 | function. So, if you highlighted the entire chunk below and then ran the
140 | `Align Assign` addin…
141 |
142 | ``` r
143 | var1 <- letters
144 | var2 <- as.list(sample(1:26, 26))
145 | names(var2) <- var1[unlist(var2)]
146 | list.pos <- function(name, lst){
147 | matches <- sapply(name, function(x){
148 | matched <- which(names(lst) %in% x)
149 |
150 | if(length(matched) == 0) matched <- NA
151 | matched
152 | })
153 | return(matches)
154 | }
155 | positions <- list.pos(c("a", "bbb", "c"), var2)
156 | ```
157 |
158 | …the result will look like this.
159 |
160 | ``` r
161 | var1 <- letters
162 | var2 <- as.list(sample(1:26, 26))
163 | names(var2) <- var1[unlist(var2)]
164 | list.pos <- function(name, lst){
165 | matches <- sapply(name, function(x){
166 | matched <- which(names(lst) %in% x)
167 |
168 | if(length(matched) == 0) matched <- NA
169 | matched
170 | })
171 | return(matches)
172 | }
173 | positions <- list.pos(c("a", "bbb", "c"), var2)
174 | ```
175 |
--------------------------------------------------------------------------------
/inst/media/Thumbs.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seasmith/AlignAssign/1811a06847825868bc655a1c64781c94e797a3da/inst/media/Thumbs.db
--------------------------------------------------------------------------------
/inst/media/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seasmith/AlignAssign/1811a06847825868bc655a1c64781c94e797a3da/inst/media/demo.gif
--------------------------------------------------------------------------------
/inst/media/demo2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seasmith/AlignAssign/1811a06847825868bc655a1c64781c94e797a3da/inst/media/demo2.gif
--------------------------------------------------------------------------------
/inst/media/demo_cursors.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seasmith/AlignAssign/1811a06847825868bc655a1c64781c94e797a3da/inst/media/demo_cursors.gif
--------------------------------------------------------------------------------
/inst/rstudio/addins.dcf:
--------------------------------------------------------------------------------
1 | Name: Align Assign
2 | Description: Aligns '<-' or '=' assignment operators within a highlighted area.
3 | Binding: alignAssign
4 | Interactive: false
5 |
6 | Name: Align Cursors
7 | Description: Aligns all cursors. Use Ctrl/Cmd + Alt + click to insert multiple cursors.
8 | Binding: alignCursor
9 | Interactive: false
10 |
11 | Name: Align Assign Arrow
12 | Description: Aligns '<-' assignment operators within a highlighted area.
13 | Binding: alignAssignArrow
14 | Interactive: false
15 |
16 | Name: Align Assign Equal
17 | Description: Aligns assignment '=' operators within a highlighted area.
18 | Binding: alignAssignEqual
19 | Interactive: false
20 |
--------------------------------------------------------------------------------
/man/alignAssign.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/align_assign.R
3 | \name{alignAssign}
4 | \alias{alignAssign}
5 | \title{Align a highlighted region's assignment operators.}
6 | \usage{
7 | alignAssign(rgx_op = NULL)
8 | }
9 | \arguments{
10 | \item{rgx_op}{Regex for assignment operator}
11 | }
12 | \value{
13 | Aligns the given or guessed operator within a highlighted region.
14 | }
15 | \description{
16 | Align a highlighted region's assignment operators.
17 | }
18 |
--------------------------------------------------------------------------------
/man/alignAssignArrow.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/align_assign.R
3 | \name{alignAssignArrow}
4 | \alias{alignAssignArrow}
5 | \title{Align a highlighted region's assignment operators.}
6 | \usage{
7 | alignAssignArrow()
8 | }
9 | \value{
10 | Aligns the single caret operators (\code{<-}) within a
11 | highlighted region.
12 | }
13 | \description{
14 | Align a highlighted region's assignment operators.
15 | }
16 |
--------------------------------------------------------------------------------
/man/alignAssignEqual.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/align_assign.R
3 | \name{alignAssignEqual}
4 | \alias{alignAssignEqual}
5 | \title{Align a highlighted region's assignment operators.}
6 | \usage{
7 | alignAssignEqual()
8 | }
9 | \value{
10 | Aligns the equal sign assignment operators (\code{=}) within a
11 | highlighted region.
12 | }
13 | \description{
14 | Align a highlighted region's assignment operators.
15 | }
16 |
--------------------------------------------------------------------------------