Skip to content

Commit

Permalink
Merge pull request #606 from kkoomen/feature/implement-r
Browse files Browse the repository at this point in the history
Add support for R
  • Loading branch information
kkoomen authored Aug 12, 2023
2 parents 8c57301 + 9b21832 commit d6ab9a0
Show file tree
Hide file tree
Showing 13 changed files with 316 additions and 81 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Is your favorite doc standard not supported?
| :white_check_mark: | C# | [XMLDoc][xmldoc] |
| :white_check_mark: | Bash | [Google][sh-google] |
| :white_check_mark: | Rust | [RustDoc][rustdoc] |
| :white_check_mark: | R | [Roxygen2][roxygen2] |

# Getting started

Expand Down Expand Up @@ -172,6 +173,7 @@ Here is the full list of available doc standards per filetype:
| `g:doge_doc_standard_sh` | `'google'` | `'google'` |
| `g:doge_doc_standard_rs` | `'rustdoc'` | `'rustdoc'` |
| `g:doge_doc_standard_cs` | `'xmldoc'` | `'xmldoc'` |
| `g:doge_doc_standard_r` | `'roxygen2'` | `'roxygen2'` |

## Options

Expand Down Expand Up @@ -468,6 +470,7 @@ Vim-doge is licensed under the GPL-3.0 license.
[kerneldoc]: https://www.kernel.org/doc/html/latest/doc-guide/kernel-doc.html
[sh-google]: https://google.github.io/styleguide/shell.xml#Function_Comments
[xmldoc]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/
[roxygen2]: https://github.com/klutometis/roxygen

[demo-readme]: https://github.com/kkoomen/vim-doge/blob/master/doc/demos
[suggest-language]: https://github.com/kkoomen/vim-doge/issues/new?labels=enhancement&template=feature_request.md&title=Add+support+for+<language>
Expand Down
81 changes: 0 additions & 81 deletions ftplugin/_r.vim

This file was deleted.

11 changes: 11 additions & 0 deletions ftplugin/r.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
let s:save_cpo = &cpoptions
set cpoptions&vim

let b:doge_parser = 'r'
let b:doge_insert = 'above'

let b:doge_supported_doc_standards = ['roxygen2']
let b:doge_doc_standard = doge#buffer#get_doc_standard('r')

let &cpoptions = s:save_cpo
unlet s:save_cpo
10 changes: 10 additions & 0 deletions helper/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions helper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ tree-sitter-c = { git = "https://github.com/tree-sitter/tree-sitter-c", rev = "8
tree-sitter-cpp = { git = "https://github.com/tree-sitter/tree-sitter-cpp", rev = "0e7b7a0" }
tree-sitter-typescript = { git = "https://github.com/tree-sitter/tree-sitter-typescript", rev = "3429d8c" }
tree-sitter-php = { git = "https://github.com/tree-sitter/tree-sitter-php", rev = "d43130f" }
tree-sitter-r = { git = "https://github.com/r-lib/tree-sitter-r", rev = "c55f8b4" }
1 change: 1 addition & 0 deletions helper/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub fn load_doc_config_str<'a>(parser_name: &'a str, doc_name: &'a str) -> &'a s
"csharp_xmldoc" => include_str!("csharp/docs/xmldoc.yaml"),
"bash_google" => include_str!("bash/docs/google.yaml"),
"rust_rustdoc" => include_str!("rust/docs/rustdoc.yaml"),
"r_roxygen2" => include_str!("r/docs/roxygen2.yaml"),

_ => panic!("Unsupported {} doc: {}", parser_name, doc_name),
}
Expand Down
2 changes: 2 additions & 0 deletions helper/src/docblock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::python::parser::PythonParser;
use crate::ruby::parser::RubyParser;
use crate::rust::parser::RustParser;
use crate::typescript::parser::TypescriptParser;
use crate::r::parser::RParser;


fn replace_indent_placeholders(docblock: &str, use_tabs: bool, indent: usize) -> String {
Expand Down Expand Up @@ -137,6 +138,7 @@ pub fn generate(
"c" => Box::new(CParser::new(code, line, &node_types)) as Box<dyn BaseParser>,
"cpp" => Box::new(CppParser::new(code, line, &node_types)) as Box<dyn BaseParser>,
"typescript" => Box::new(TypescriptParser::new(code, line, &node_types, options)) as Box<dyn BaseParser>,
"r" => Box::new(RParser::new(code, line, &node_types)) as Box<dyn BaseParser>,
_ => panic!("Unsupported parser: {}", &parser_name),
};

Expand Down
1 change: 1 addition & 0 deletions helper/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ pub mod python;
pub mod c;
pub mod cpp;
pub mod typescript;
pub mod r;
25 changes: 25 additions & 0 deletions helper/src/r/docs/roxygen2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# https://github.com/klutometis/roxygen

templates:
function:
node_types:
- function_definition
template: |
#' [TODO:title of the function]
#'
#' [TODO:brief description]
{% if params %}
#'
{% for param in params %}
#' @param {{ param.name }} [TODO:description]{% if param.default_value %}. Default is {{ param.default_value }}.{% endif %}
{% endfor %}
{% endif %}
#'
#' @return [TODO:description]
#'
#' @examples
#' {{ func_name }}([TODO:parameters])
#'
#' @rdname {{ func_name }}
#'
#' @method {{ func_name }}
1 change: 1 addition & 0 deletions helper/src/r/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod parser;
110 changes: 110 additions & 0 deletions helper/src/r/parser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use tree_sitter::{Parser, Node};
use serde_json::{Map, Value};

use crate::base_parser::BaseParser;
use crate::traverse;

pub struct RParser<'a> {
code: &'a str,
tree: tree_sitter::Tree,
line: &'a usize,
node_types: &'a [&'a str],
}

impl<'a> BaseParser for RParser<'a> {
fn parse(&self) -> Option<Result<Map<String, Value>, String>> {
self.parse_node(&self.tree.root_node())
}

fn get_code_bytes(&self) -> &[u8] {
&self.code.as_bytes()
}
}

impl<'a> RParser<'a> {
pub fn new(code: &'a str, line: &'a usize, node_types: &'a [&'a str]) -> Self {
let mut parser = Parser::new();
parser.set_language(tree_sitter_r::language()).unwrap();

let tree = parser.parse(code, None).unwrap();

Self { code, tree, line, node_types }
}

fn parse_node(&self, node: &Node) -> Option<Result<Map<String, Value>, String>> {
for child_node in traverse::PreOrder::new(node.walk()) {
if child_node.start_position().row + 1 == *self.line && self.node_types.contains(&child_node.kind()) {
return match child_node.kind() {
"function_definition" => Some(self.parse_function(&child_node)),
_ => None,
};
}
}

None
}

fn parse_function(&self, node: &Node) -> Result<Map<String, Value>, String> {
let mut tokens = Map::new();

if let Some(parent_node) = node.parent() {
let func_name = parent_node
.children(&mut parent_node.walk())
.filter(|node| node.kind() == "identifier")
.next()
.and_then(|node| Some(self.get_node_text(&node)))
.unwrap();
tokens.insert("func_name".to_string(), Value::String(func_name));
}

for child_node in node.children(&mut node.walk()) {
match child_node.kind() {
"formal_parameters" => {
let mut params = Vec::new();

for grandchild_node in child_node.children(&mut child_node.walk()) {
let mut param = Map::new();

match grandchild_node.kind() {
"identifier" | "dots" => {
param.insert("name".to_string(), Value::String(self.get_node_text(&grandchild_node)));
},
"default_parameter" => {
let name = grandchild_node
.children(&mut grandchild_node.walk())
.filter(|node| node.kind() == "identifier")
.next()
.and_then(|node| Some(self.get_node_text(&node)))
.unwrap();

let default_value = grandchild_node
.children(&mut grandchild_node.walk())
.filter(|node| node.kind() == "=")
.next()
.unwrap()
.next_sibling()
.and_then(|node| Some(self.get_node_text(&node)))
.unwrap();

param.insert("name".to_string(), Value::String(name));
param.insert("default_value".to_string(), Value::String(default_value));
},
_ => {},
}

if !param.is_empty() {
params.push(Value::Object(param));
}
}

if !params.is_empty() {
tokens.insert("params".to_string(), Value::Array(params));
}
},
_ => {},
}
}

Ok(tokens)
}
}
20 changes: 20 additions & 0 deletions helper/test.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
myFunc.default <- function() {}

myFunc.default <- function(
p1,
p2.sub1 = FALSE,
p3.sub1 = 20,
p4.sub1 = 1/15,
...
) {
# ...
}

myFunc = function(
p1 = TRUE, p2_sub1= TRUE, p3 = FALSE,
p4 = 'libs', p5 = NULL, ..., p7 = 'default',
p8 = c('lorem', 'ipsum+dor', 'sit', 'amet'),
p9 = TRUE, p10 = list(), p11 = TRUE
) {
# ...
}
Loading

0 comments on commit d6ab9a0

Please sign in to comment.