Skip to content

Commit 952942d

Browse files
committed
Merge pull request #69 from lorenzwalthert/indent_with_renesting
- Fix indention of long operator chains. - Properly format unary operators (#38).
2 parents 6b2d117 + 1513f64 commit 952942d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1528
-355
lines changed

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ importFrom(purrr,partial)
1818
importFrom(purrr,pmap)
1919
importFrom(purrr,pwalk)
2020
importFrom(purrr,reduce)
21+
importFrom(purrr,when)
2122
importFrom(utils,write.table)

R/get_transformers.R

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ get_transformers_nested <- function(strict = TRUE,
5959
c(create_filler,
6060
partial(indent_round, indent_by = indent_by),
6161
partial(indent_curly, indent_by = indent_by),
62+
partial(indent_op, indent_by = indent_by),
6263
strip_eol_spaces,
6364
get_transformers_flat(strict, start_comments_with_one_space),
65+
remove_space_after_unary_pm_nested,
6466
set_space_before_comments,
6567
set_space_between_levels
6668
)

R/modify_pd.R

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#' @param pd A nested or flat parse table that is already enhanced with
44
#' line break and space information via [create_filler()].
55
#' @param indent_by How many spaces should be added after the token of interest.
6+
#' @param token The token the indention should be based on.
67
#' @name update_indention
78
NULL
89

@@ -76,6 +77,12 @@ child_indents <- function(pd, opening, token) {
7677

7778
#' Check whether a parse table contains a token
7879
#'
80+
#' Checks whether a token is in a parse table. `pd_has_token_not_one` is usesful
81+
#' in the situation where one wants to check whether the *operator* + or - is
82+
#' in the parse table, but not the *sign* + or -.
83+
#' We use the fact that signs always appear as first tokens in the parse
84+
#' table. There are two functions and not just one for performance reasons
85+
#' only, as this function is rather low level and gets called very often.
7986
#' @param pd A parse table.
8087
#' @param token The token for which it should be checked whether it is in the
8188
#' parse table.
@@ -85,6 +92,29 @@ pd_has_token <- function(pd, token) {
8592
any(has_indention_token)
8693
}
8794

95+
#' @rdname pd_has_token
96+
pd_has_token_not_first <- function(pd, token) {
97+
has_indention_token <- token %in% pd$token[-1]
98+
any(has_indention_token)
99+
}
100+
101+
102+
#' @rdname update_indention
103+
indent_op <- function(pd, indent_by, token = c(math_token, "SPECIAL")) {
104+
opening <- which(pd$token %in% token)
105+
if (length(opening) > 0) {
106+
start <- opening[1] + 1
107+
stop <- nrow(pd)
108+
} else {
109+
start <- stop <- 0
110+
}
111+
pd <- pd %>%
112+
mutate(indent = indent + ifelse(seq_len(nrow(pd)) %in% start:stop, indent_by, 0)) %>%
113+
select_(~indent, ~newlines, ~everything())
114+
pd
115+
}
116+
117+
88118
#' Strip EOL spaces
89119
#'
90120
#' Remove end-of-line spaces.

R/nested_to_tree.R

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22
#'
33
#' Create a tree representation from a text.
44
#' @param text A character vector.
5+
#' @param re_nest Whether or not the parse table should be renested with
6+
#' [re_nest()].
57
#' @return A data frame.
6-
create_tree <- function(text) {
8+
#' @importFrom purrr when
9+
create_tree <- function(text, re_nest = FALSE) {
710
compute_parse_data_nested(text) %>%
8-
visit(c(styler:::create_filler)) %>%
11+
visit(c(create_filler)) %>%
12+
when(re_nest ~ re_nest(.), ~.) %>%
913
create_node_from_nested_root() %>%
1014
as.data.frame()
1115
}

R/relevel.R

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#' Reorganize a nested parse table
2+
#'
3+
#' Certain tokens are not placed optimally in the nested parse data with
4+
#' [compute_parse_data_nested()]. For example, the token of arithmetic
5+
#' operations 1 + 1 + 1 should all be on the same level of nesting since
6+
#' the indention is the same for all but the first two terminals. Setting the
7+
#' indention correcly is easier to achieve if they are put on the same level
8+
#' of nesting.
9+
#' @examples
10+
#' code <- "1+1+1+1"
11+
#' # tree-structure with compute_parse_data_nested
12+
#' styler:::create_tree(code, re_nest = FALSE)
13+
#' # tree-structure with re_nest post-processing
14+
#' styler:::create_tree(code, re_nest = TRUE)
15+
#' @inheritParams move_children_up
16+
re_nest <- function(pd_nested) {
17+
if (is.null(pd_nested)) return()
18+
pd_nested <- pd_nested %>%
19+
move_children_up(token = c("'+'", "'-'", "SPECIAL", "'/'", "'*'")) %>%
20+
mutate(child = map(child, re_nest))
21+
pd_nested
22+
}
23+
24+
#' Move children up if appropriate
25+
#'
26+
#' Move children one level of nesting up if necessary. If any was moved up,
27+
#' check again whether any child of the former child should be moved up in a
28+
#' recursive way.
29+
#' @param pd_nested A nested parse table to reorganize.
30+
#' @param token Character vector with tokens that can cause a child to be moved
31+
#' up.
32+
#' @details A child is moved up under the following conditions:
33+
#'
34+
#' * The parent of the child to be considered for moving up (that is simply
35+
#' the corresponding row in `pd_nested`) is not a top-level expression.
36+
#' Otherwise, the second expression may be indented due to operator
37+
#' indention(e.g. in "1+1; 1+1").
38+
#' * The child has one of `token` in the parse table. The first token is not
39+
#' considered to propper handle signs (see [pd_has_token_not_first()]).
40+
#' * One of `token` also appears before or after the child in `pd_nested`.
41+
#' For example, there is no need to move any child up in the expression
42+
#' "{1+1}", since then, operator and bracket indention would conflict.
43+
#' @importFrom purrr map_lgl
44+
move_children_up <- function(pd_nested,
45+
token = c("'+'", "'-'", "SPECIAL", "'/'", "'*'")) {
46+
47+
move_up <- pd_nested$parent > 0 &
48+
map_lgl(pd_nested$child, pd_has_token_not_first, token) &
49+
token_is_adjacent(pd_nested, token)
50+
51+
out <- bind_rows(pd_nested, pd_nested$child[move_up]) %>%
52+
mutate(old_parent = id %in% parent) %>%
53+
filter(!old_parent) %>%
54+
select(-old_parent) %>%
55+
arrange(line1, col1)
56+
if (any(move_up)) {
57+
out <- re_nest(out)
58+
} else {
59+
out
60+
}
61+
}
62+
63+
#' Are they neighbours?
64+
#'
65+
#' Check whether a token is positioned next to another token in a parse table.
66+
#' @param pd A parse table.
67+
#' @param token A vector of tokens to check.
68+
token_is_adjacent <- function(pd, token) {
69+
lead <- lead(pd$token %in% token, default = FALSE)
70+
lag <- lag(pd$token %in% token, default = FALSE)
71+
lead | lag
72+
}

R/rules.R

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
math_token <- c("'+'", "'-'", "'*'", "'/'", "'^'")
12
op_token <- c(
2-
"'+'", "'-'", "'*'", "'/'", "'^'", "AND", "AND2", "EQ", "EQ_ASSIGN",
3+
math_token, "AND", "AND2", "EQ", "EQ_ASSIGN",
34
"GE", "GT", "LE", "LEFT_ASSIGN", "LT", "NE", "OR", "OR2", "RIGHT_ASSIGN",
45
"SPECIAL", "EQ_SUB", "ELSE")
56

@@ -21,6 +22,7 @@ set_space_around_op <- function(pd_flat) {
2122
pd_flat
2223
}
2324

25+
# depreciated!
2426
remove_space_after_unary_pm <- function(pd_flat) {
2527
op_pm <- c("'+'", "'-'")
2628
op_pm_unary_after <- c(op_pm, op_token, "'('", "','")
@@ -31,6 +33,16 @@ remove_space_after_unary_pm <- function(pd_flat) {
3133
pd_flat
3234
}
3335

36+
37+
remove_space_after_unary_pm_nested <- function(pd) {
38+
if (any(c("'+'", "'-'") %in% pd$token[1])) {
39+
pd$spaces[1] <- 0L
40+
}
41+
42+
pd
43+
}
44+
45+
3446
fix_quotes <- function(pd_flat) {
3547
str_const <- pd_flat$token == "STR_CONST"
3648
str_const_change <- grepl("^'([^\"]*)'$", pd_flat$text[str_const])

R/serialized_tests.R

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
#' @inheritParams transform_and_check
2323
#' @importFrom purrr flatten_chr pwalk map
2424
test_collection <- function(test, sub_test = NULL,
25-
write_back = FALSE,
25+
write_back = TRUE,
2626
write_tree = TRUE,
2727
transformer,
2828
...) {
@@ -180,3 +180,15 @@ style_indent_curly_round <- function(text) {
180180

181181
serialize_parse_data_nested()
182182
}
183+
184+
#' @describeIn test_transformer Transformations for indention based on operators
185+
style_op <- function(text) {
186+
text %>%
187+
compute_parse_data_nested() %>%
188+
re_nest() %>%
189+
visit(funs = c(create_filler,
190+
partial(indent_op, indent_by = 2),
191+
strip_eol_spaces)) %>%
192+
193+
serialize_parse_data_nested()
194+
}

R/transform.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ make_transformer_nested <- function(transformers) {
7373
text <- gsub("\t", " ", text)
7474

7575
pd_nested <- compute_parse_data_nested(text)
76+
pd_nested <- re_nest(pd_nested)
7677
transformed_pd_nested <- visit(pd_nested, transformers)
7778
# TODO verify_roundtrip
7879
new_text <- serialize_parse_data_nested(transformed_pd_nested)

man/create_tree.Rd

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/move_children_up.Rd

Lines changed: 33 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)