Skip to content

Commit 1b76fca

Browse files
authored
Add support for R (#47)
Nice work! Thank you for the tests and scm comments.
1 parent 9efaddf commit 1b76fca

File tree

6 files changed

+145
-0
lines changed

6 files changed

+145
-0
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ tree-sitter-html = "<0.25.0"
3939
tree-sitter-javascript = "<0.25.0"
4040
tree-sitter-php = "<0.24.0"
4141
tree-sitter-python = "<0.25.0"
42+
tree-sitter-r = "1.1.0"
4243
tree-sitter-ruby = "0.23.1"
4344
tree-sitter-rust = "<0.25.0"
4445
tree-sitter-toml-ng = "<0.8.0"

crates/codebook/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ tree-sitter-html.workspace = true
1515
tree-sitter-javascript.workspace = true
1616
tree-sitter-php.workspace = true
1717
tree-sitter-python.workspace = true
18+
tree-sitter-r.workspace = true
1819
tree-sitter-ruby.workspace = true
1920
tree-sitter-rust.workspace = true
2021
tree-sitter-toml-ng.workspace = true

crates/codebook/src/queries.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub enum LanguageType {
1212
Javascript,
1313
Php,
1414
Python,
15+
R,
1516
Ruby,
1617
Rust,
1718
TOML,
@@ -136,6 +137,13 @@ pub static LANGUAGE_SETTINGS: &[LanguageSetting] = &[
136137
query: include_str!("queries/php.scm"),
137138
extensions: &["php"],
138139
},
140+
LanguageSetting {
141+
type_: LanguageType::R,
142+
ids: &["r"],
143+
dictionary_ids: &["r"],
144+
query: include_str!("queries/r.scm"),
145+
extensions: &["r", "R"],
146+
},
139147
];
140148

141149
#[derive(Debug)]
@@ -159,6 +167,7 @@ impl LanguageSetting {
159167
LanguageType::Javascript => Some(tree_sitter_javascript::LANGUAGE.into()),
160168
LanguageType::Php => Some(tree_sitter_php::LANGUAGE_PHP.into()),
161169
LanguageType::Python => Some(tree_sitter_python::LANGUAGE.into()),
170+
LanguageType::R => Some(tree_sitter_r::LANGUAGE.into()),
162171
LanguageType::Ruby => Some(tree_sitter_ruby::LANGUAGE.into()),
163172
LanguageType::Rust => Some(tree_sitter_rust::LANGUAGE.into()),
164173
LanguageType::TOML => Some(tree_sitter_toml_ng::LANGUAGE.into()),

crates/codebook/src/queries/r.scm

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
(comment) @comment
2+
(string) @string
3+
4+
(parameter name: (identifier) @identifier)
5+
6+
(binary_operator
7+
lhs: (identifier) @identifier
8+
operator: ["<-" "="])
9+
(binary_operator
10+
operator: "->"
11+
rhs: (identifier) @identifier)
12+
13+
;---------------------------------------
14+
; Less clear-cut spell checking targets:
15+
;---------------------------------------
16+
17+
; Functions with ... args sometimes use the argument names similarly to
18+
; new variable definitions which should be spell-checked.
19+
; e.g. dplyr::mutate(data_table, new_column_name=col_a + col_b) should check `new_column_name`
20+
(argument name: (identifier) @identifier)
21+
22+
; Assignments with `$` can similarly define new names
23+
; For chains, only check the last name since the earlier names are not being newly defined
24+
; e.g. `my_list$data_table$new_column_name <- 1 + 2` should check `new_column_name`
25+
(binary_operator
26+
lhs: (extract_operator
27+
operator: "$"
28+
rhs: (identifier) @identifier)
29+
operator: ["<-" "="])
30+
31+
(binary_operator
32+
operator: "->"
33+
rhs: (extract_operator
34+
operator: "$"
35+
rhs: (identifier) @identifier))

crates/codebook/tests/test_r.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
use codebook::queries::LanguageType;
2+
mod utils;
3+
4+
#[test]
5+
fn test_r_simple() {
6+
utils::init_logging();
7+
let processor = utils::get_processor();
8+
let sample_text = r#"
9+
calculatr <- function(numbr1, argumnt2=3) {
10+
# This is an exampl function
11+
numberr1 + argument2
12+
}
13+
"#;
14+
let expected = vec!["argumnt", "calculatr", "exampl", "numbr"];
15+
let binding = processor
16+
.spell_check(sample_text, Some(LanguageType::R), None)
17+
.to_vec();
18+
let mut misspelled = binding
19+
.iter()
20+
.map(|r| r.word.as_str())
21+
.collect::<Vec<&str>>();
22+
misspelled.sort();
23+
assert_eq!(misspelled, expected);
24+
}
25+
26+
#[test]
27+
fn test_r_string() {
28+
utils::init_logging();
29+
let processor = utils::get_processor();
30+
let sample_text = r#"
31+
my_var <- "herlo, world"
32+
"#;
33+
let expected = vec!["herlo"];
34+
let binding = processor
35+
.spell_check(sample_text, Some(LanguageType::R), None)
36+
.to_vec();
37+
let mut misspelled = binding
38+
.iter()
39+
.map(|r| r.word.as_str())
40+
.collect::<Vec<&str>>();
41+
misspelled.sort();
42+
assert_eq!(misspelled, expected);
43+
}
44+
45+
#[test]
46+
fn test_r_kwarg() {
47+
utils::init_logging();
48+
let processor = utils::get_processor();
49+
let sample_text = r#"
50+
table2 <- dplyr::mutate(table1, mispell=nmae1 + name2, bad_spelin, olny_named_cols=3)
51+
"#;
52+
let expected = vec!["mispell", "olny"];
53+
let binding = processor
54+
.spell_check(sample_text, Some(LanguageType::R), None)
55+
.to_vec();
56+
let mut misspelled = binding
57+
.iter()
58+
.map(|r| r.word.as_str())
59+
.collect::<Vec<&str>>();
60+
misspelled.sort();
61+
assert_eq!(misspelled, expected);
62+
}
63+
64+
#[test]
65+
fn test_r_assign() {
66+
utils::init_logging();
67+
let processor = utils::get_processor();
68+
let sample_text = r#"
69+
list$miispell = list()
70+
list$mispell$chiian <- 1
71+
list$mispell$chainn[1:3] <- 2 # Should not get checked
72+
list$ingore@atsigns = 3
73+
4 -> right@atsigns$wroks
74+
lerft -> rihgt # Only right-side gets checked
75+
leeft <- 3
76+
lefft = 2
77+
"#;
78+
let expected = vec!["chiian", "leeft", "lefft", "miispell", "rihgt", "wroks"];
79+
let binding = processor
80+
.spell_check(sample_text, Some(LanguageType::R), None)
81+
.to_vec();
82+
let mut misspelled = binding
83+
.iter()
84+
.map(|r| r.word.as_str())
85+
.collect::<Vec<&str>>();
86+
misspelled.sort();
87+
assert_eq!(misspelled, expected);
88+
}

0 commit comments

Comments
 (0)