Skip to content

Addin to style highlighted region #143

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Aug 31, 2017

Conversation

lorenzwalthert
Copy link
Collaborator

This closes #107. It seems a bit complicated because of the fact that you can highlight also just parts of lines. Did not really know how we could add formal testing to that. One way would be to make context an argument of style_active_region() with default find_active_context() so we can supply some file region for testing purposes.

@lorenzwalthert lorenzwalthert requested a review from krlmlr August 21, 2017 17:02
@lorenzwalthert lorenzwalthert force-pushed the rstudioaddin branch 4 times, most recently from fa679c7 to d85a54d Compare August 21, 2017 17:08
@codecov
Copy link

codecov bot commented Aug 21, 2017

Codecov Report

Merging #143 into master will decrease coverage by 0.58%.
The diff coverage is 82.14%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #143      +/-   ##
==========================================
- Coverage   93.85%   93.26%   -0.59%     
==========================================
  Files          19       20       +1     
  Lines         748      802      +54     
==========================================
+ Hits          702      748      +46     
- Misses         46       54       +8
Impacted Files Coverage Δ
R/ws.R 96% <ø> (+7.11%) ⬆️
R/serialized_tests.R 100% <100%> (ø) ⬆️
R/addins.R 81.81% <81.81%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update dd23ac9...76ca7ec. Read the comment docs.

Copy link
Member

@krlmlr krlmlr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if the addin should operate in interactive mode, because there seems to be no feedback otherwise, e.g., when styling the entire package.

Also, styling the active region doesn't seem to work if an incomplete expression is selected. We could search for the sub-tibble that fully contains the selected region and style only this, but that's worth a separate issue.

@lorenzwalthert
Copy link
Collaborator Author

Yes, I thought about that too. I think it gives feedback, e.g. "No files changed" appears on the console but I think the problem is also that the error handling is not very good. Same with the other Addins, although I think the "style active file"-Addin is the most important one. The reason I have not explored interactive Addins is that I can't do that as part of Milestone CRAN due to time constraints. Should we leave it as is or should we keep all Addins for a future CRAN release?

@krlmlr
Copy link
Member

krlmlr commented Aug 22, 2017

"Interactive" just means that it runs in the active R session, and blocks it -- a simple change to inst/rstudio/addins.dcf, not a GUI or anything.

@lorenzwalthert
Copy link
Collaborator Author

Ok, I see. Let's do that then.

@lorenzwalthert
Copy link
Collaborator Author

It actually does not work the way I thought because we use the RStudio API to get the active document. If we set interactive = TRUE, the Addin is executed in the console and can't get the active document context. So this mode would only work as a short cut for style_pkg() but not for styling the active file or the highlighted region on the active file.

@krlmlr
Copy link
Member

krlmlr commented Aug 23, 2017

rstudioapi::getActiveDocumentContext() works for me when I run it from the console. What's the difference to an interactive add-in?

@lorenzwalthert
Copy link
Collaborator Author

lorenzwalthert commented Aug 23, 2017

Oh now it works, had to restart RStudio also, not just rebuild the package and restart R. With regard to tests, do you think we should make context an argument as stated above?

@krlmlr
Copy link
Member

krlmlr commented Aug 24, 2017

You could implement:

style_active_region <- function() {
  context <- find_active_context()
  all_text <- utf8::read_lines_enc(context$path)
  ...
}

get_rstudio_context <- function() {
  rstudioapi::getActiveDocumentContext()
}

and then in the test ask

test_that("...", {
  result <- mockr::with_mock(
    get_rstudio_context = function() structure(list(...), class = "document_context"),
    style_active_region()
  )
  expect...(result, ...)
})

@lorenzwalthert
Copy link
Collaborator Author

lorenzwalthert commented Aug 27, 2017

I tried to use mockr but when running this test_that() statement interactively, it gave me an error with mockr::with_mock(), but not with testthat::with_mock(). When running via devtools::test(f = "public"), both did not give an error. I used testhat for now, maybe @krlmlr can have a look why that happends? Also, I did not mock get_rstudio_context() but find_active_context() since this function is the one that gets called by the function we want to test and I was not sure whether it was possible to mock functions that are not directly called by the function we want to test.

@lorenzwalthert lorenzwalthert requested a review from krlmlr August 28, 2017 08:21
Copy link
Member

@krlmlr krlmlr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with postponing automated tests. Maybe split this PR so that the testing is added in a separate commit/branch?

R/addins.R Outdated
#'
#' Helper function for RStudio Addin.
style_active_file <- function() {
file <- rstudioapi::getActiveDocumentContext()$path
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need to call find_active_context() here to allow mocking?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want I guess so. So far, only style_actige_region is tested but we can add a test here too to increase coverage.

R/addins.R Outdated
path <- context$path
start <- context$selection[[1]]$range$start
end <- context$selection[[1]]$range$end
if (all(start == end)) return()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... and then return a list with only one component here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should rather be stop("No region selected") instead of return().

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if we want to call this for getting the active file?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No then not. But currently, we don't use find_active_context() for styling files. Should we? If yes, then the error message should not be implemented within the function find_active_context, I agree.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's currently only used for styling regions within files.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I adapted it so it is used in both cases.

@@ -17,3 +17,37 @@ test_that("styler can style file", {
})

# style_active_file() must be tested manually.
test_that("...", {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops

before_styling <- utf8::read_lines_enc(paste0(base, "/xyzaddin/addin_region-in.R"))
reference <- utf8::read_lines_enc(paste0(base, "/xyzaddin/addin_region-out.R"))
result <- expect_error(
testthat::with_mock(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mockr::with_mock() should really work here, because testthat::with_mock() might not at some point. Can you please simplify the code (e.g., extract the hard-coded "document_context" structure to a variable) and try again? For troubleshooting the error message is helpful.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mockr::with_mock() works using devtools::test() but not interactively while testthat::with_mock() works in both sistuations, which is why I have not used mockr yet. Can you have a look at why that is the case?

What do you mean with extracting hard-coded "document_context" structure to a variable? Like this?

doc_cont <- structure(...)
testthat("...", {
  result <- mockr::with_mock(
    get_rstudio_context = function() doc_cont, 
    ...

Unfortunately, there is no way to create the structure with a function call directly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, something like this code.

You could try mockr::with_mock(..., envir = asNamespace("styler")) .

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so assign the variable elsewhere in the name space? Or should leave the declaration where it is?

R/addins.R Outdated
#' [rstudioapi::getActiveDocumentContext()].
#'
find_active_context <- function() {
context <- rstudioapi::getActiveDocumentContext()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we could just create a simple forwarder to rstudioapi::getActiveDocumentContext() in our package, and mock this forwarder:

get_rstudio_context <- function() {
  rstudioapi::getActiveDocumentContext()
}

mockr still works if functions are called indirectly from our package (it patches all functions in our package).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok yes I see. That's what I a say unsure about (see comment above).

@krlmlr
Copy link
Member

krlmlr commented Aug 29, 2017

Do you need more input here?

@lorenzwalthert lorenzwalthert force-pushed the rstudioaddin branch 2 times, most recently from bde246e to fc426a9 Compare August 29, 2017 11:45
@lorenzwalthert lorenzwalthert requested a review from krlmlr August 29, 2017 11:48
@lorenzwalthert
Copy link
Collaborator Author

Can you review the updated PR?

Copy link
Member

@krlmlr krlmlr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks. If you call devtools::release(), one of the first things it does is a spell check of the documentation, this will find the typos we've missed.

R/styler.R Outdated
#' according to a style guide. See the INDEX for more information.
#'
#' according to a style guide.
#' The fo,lowing functions can be used for styling:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes


before_styling <- utf8::read_lines_enc(paste0(base, "/xyzaddin/addin_region-in.R"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just copy to a temporary directory?

dir <- tempfile("styler")
dir.create(dir)
file.copy(".../addin_region-out.R", dir)

The current approach seems slightly brittle if the tests aborts before the original contents have been written.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, right. So if I understand you right, we copy the *-in.R* to the temporary directory, style it there and compare it with the -*out. in the permanent directory?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

R/addins.R Outdated
#'
#' Essentially adding the parts before the highlighted area on the line where
#' the higlighted area starts to the styled expression. Also, after the styled
#' expression, the remainer of that line that was not styled is added.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remainder?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

@lorenzwalthert lorenzwalthert mentioned this pull request Aug 30, 2017
@lorenzwalthert lorenzwalthert force-pushed the rstudioaddin branch 2 times, most recently from 688e4a5 to 5516951 Compare August 30, 2017 11:01
@lorenzwalthert lorenzwalthert changed the title Add in to style highlighted region Addin to style highlighted region Aug 30, 2017
Copy link
Member

@krlmlr krlmlr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, but we might need yet another iteration.

README.md Outdated
@@ -23,7 +23,7 @@ There are a few variants of `style_text()`:
- `style_file()` styles a single .R file.
- `style_dir()` styles all .R files in a directory.
- `style_pkg()` styles the source files of an R package.
- An RStudio Addin that styles the active file .R file
- RStudio Addins for styling the active file, styling current package and styling the highlighted code region.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the current package?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the package which has its root in the current working directory (if any). Could not find a better formulation for it. Any ideas?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

styling current package -> styling the current package

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?


# style_active_file() must be tested manually.
test_that("styling active region works", {
reference <- utf8::read_lines_enc( paste0(base, "/xyzaddin/addin_region-out.R"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

file.path() better explains your intentions. Even better, a small function

testthat_file <- function(...) {
  file.path(rprojroot::find_testthat_root_file("public-api"), ...)
}

instead of the base variable. Here and elsewhere.

@@ -21,3 +21,39 @@ test_that("styler does not return error when there is no file to style", {
})


## ............................................................................

dir <- tempfile("styler")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these variables seem to fit better in the test_that() block below.

@@ -21,3 +21,39 @@ test_that("styler does not return error when there is no file to style", {
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would the preceding tests change the original files?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, they should not, because the input is already styled. The tests are only to check whether the call returns an error or not. It's a rather superficial test.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These files will then need an update whenever the style guide changes, but that's fine with me.

R/addins.R Outdated
list(
start = fract_of_line_start,
end = fract_of_line_end,
body = lines_not_to_style
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

body seems a misnomer if it's

the lines that are not overlapping with the highlighted text.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So maybe just lines_not_to_style?

@lorenzwalthert lorenzwalthert requested a review from krlmlr August 30, 2017 15:58
README.md Outdated
@@ -23,7 +23,7 @@ There are a few variants of `style_text()`:
- `style_file()` styles a single .R file.
- `style_dir()` styles all .R files in a directory.
- `style_pkg()` styles the source files of an R package.
- An RStudio Addin that styles the active file .R file
- RStudio Addins for styling the active file, styling current package and styling the highlighted code region.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

#' Create the path to a test that file
#' @param ... Arguments passed to [file.path()] to construct the path after
#' ".../tests/testthat/"
testthat_file <- function(...) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be better suited in a tests/testthat/helper-*.R file.

Copy link
Collaborator Author

@lorenzwalthert lorenzwalthert Aug 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. ups, forgot to knit .Rmd to md.
  2. Ok, but then we won't get roxygen2 documentation, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I forgot. Let's keep it here.

@lorenzwalthert
Copy link
Collaborator Author

@krlmlr Do you want to have a final look? I think now we got them all 😄

@lorenzwalthert lorenzwalthert merged commit ef10c29 into r-lib:master Aug 31, 2017
krlmlr added a commit that referenced this pull request Oct 23, 2017
- Hotfix: utf8 should not be verbose (#245).
- Allow styling of Rmd files(#233).
- Remove duplicate @family (#244).
- Fixing token insertion (#242).
- Capitalize Addin titles (#241).
- Explicit `NULL` creation to make styler compatible with R3.2.0 (#237).
- Improve vignettes (#232).
- Allow exclusion of files with `style_pkg()` and `style_dir()`.
- Correct styling with long strings (#230).
- Add tools for re-indenting tokens (#217).
- Math token spacing (#221).
- Remove outdated line and col information (#218).
- Empty input for styling does not cause an error (#227, #228).
- Tools to insert tokens + application on `if`-`else` clauses (#212).
- Improve example in documentation (#222).
- Fix spacing around in (#214).
- Maintenance: renaming functions / files, extend helper, documentation, if_else etc. (#204).
- Disallow line break after ( for function calls (#210).
- Preserve space between `!` and bang (#209).
- Simplify RStudio Addin (#208, #211).
- Indention based on square brackets (#207).
- Add vignette on introducing styler (#203).
- Indent function declaration without curly braces correctly (#202).
- Fix indention in if-else statement (#200).
- Sorting key (#196).
- Use safe sequences (#197).
- Fix space between two commas (#195).
- Keep single-line pipes on one line (#74).
- Remove tidyr and dplyr dependency (#182, #183, @jimhester).
- Fix parsing inconsistency (#188).
- Substitute create filler (#190).
- Introducing class vertical (#189).
- Adapt line break rules (#172).
- Fix `R CMD check` (#185).
- Force argument evaluation for proper error handling (#179).
- Add nonstrict version of set_space_before_comment (#174).
- Add installation instructions to README (#175).
- Addin to style highlighted region (#143).
- Improve spelling (#168).
- Add coverage badge
- Change badge from WIP to active
- Add the number of files to message (#166).
- Improve documentation (#164).
- Add informative messages while styling files (#165).
- More examples in help file (#161).
- No line breaks after pipe if comment is next token (#160).
- Fixing spacing around `!` (non-bang-bang) (#157).
- Finalize function documentation (#154).
- Review vignette (#158).
- Update bang-bang rule (#156).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RStudio Addin to style highlighted region of file
2 participants