Skip to content

Commit

Permalink
Add an option to print functions and their location
Browse files Browse the repository at this point in the history
  • Loading branch information
calixteman committed Dec 5, 2019
1 parent 3b36ecf commit 2e789f8
Show file tree
Hide file tree
Showing 11 changed files with 328 additions and 15 deletions.
2 changes: 1 addition & 1 deletion src/find.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ impl Callback for Find {
if !good.is_empty() {
println!("In file {:?}", cfg.path);
for node in good {
dump_node(parser.get_code(), &node, 1, cfg.line_start, cfg.line_end);
dump_node(parser.get_code(), &node, 1, cfg.line_start, cfg.line_end)?;
}
println!();
}
Expand Down
112 changes: 112 additions & 0 deletions src/function.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
use std::io::Write;
use std::path::PathBuf;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, StandardStreamLock, WriteColor};

use crate::traits::*;

use crate::checker::Checker;
use crate::getter::Getter;

#[derive(Debug, Serialize)]
pub struct FunctionSpan {
pub name: String,
pub start_line: usize,
pub end_line: usize,
pub error: bool,
}

pub fn function<T: TSParserTrait>(parser: &T) -> Vec<FunctionSpan> {
let root = parser.get_root();
let code = parser.get_code();
let mut spans = Vec::new();
root.act_on_node(&mut |n| {
if T::Checker::is_func(n) {
let start_line = n.start_position().row + 1;
let end_line = n.end_position().row + 1;
if let Some(name) = T::Getter::get_func_name(n, code) {
spans.push(FunctionSpan {
name: name.to_string(),
start_line,
end_line,
error: false,
});
} else {
spans.push(FunctionSpan {
name: "".to_string(),
start_line,
end_line,
error: true,
});
}
}
});

spans
}

fn dump_span(
span: FunctionSpan,
stdout: &mut StandardStreamLock,
last: bool,
) -> std::io::Result<()> {
/*if !span.error {
return Ok(());
}*/

let pref = if last { " `- " } else { " |- " };

color!(stdout, Blue);
write!(stdout, "{}", pref)?;

if span.error {
color!(stdout, Red, true);
write!(stdout, "error: ")?;
} else {
color!(stdout, Magenta, true);
write!(stdout, "{}: ", span.name)?;
}

color!(stdout, Green);
write!(stdout, "from line ")?;

color!(stdout, White);
write!(stdout, "{}", span.start_line)?;

color!(stdout, Green);
write!(stdout, " to line ")?;

color!(stdout, White);
writeln!(stdout, "{}.", span.end_line)
}

fn dump_spans(mut spans: Vec<FunctionSpan>, path: PathBuf) -> std::io::Result<()> {
if !spans.is_empty() {
let stdout = StandardStream::stdout(ColorChoice::Always);
let mut stdout = stdout.lock();

color!(stdout, Yellow, true);
writeln!(&mut stdout, "In file {}", path.to_str().unwrap_or("..."))?;

for span in spans.drain(..spans.len() - 1) {
dump_span(span, &mut stdout, false)?;
}
dump_span(spans.pop().unwrap(), &mut stdout, true)?;
color!(stdout, White);
}
Ok(())
}

pub struct FunctionCfg {
pub path: PathBuf,
}

pub struct Function {}

impl Callback for Function {
type Res = std::io::Result<()>;
type Cfg = FunctionCfg;

fn call<T: TSParserTrait>(cfg: Self::Cfg, parser: &T) -> Self::Res {
dump_spans(function(parser), cfg.path)
}
}
22 changes: 10 additions & 12 deletions src/getter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,6 @@ impl Getter for RustCode {
}

impl Getter for CCode {
fn get_func_name<'a>(node: &Node, code: &'a [u8]) -> Option<&'a str> {
Self::get_func_space_name(node, code)
}

fn get_func_space_name<'a>(node: &Node, code: &'a [u8]) -> Option<&'a str> {
// we're in a function_definition so need to get the declarator
if let Some(declarator) = node.child_by_field_name("declarator") {
Expand All @@ -133,7 +129,7 @@ impl Getter for CCode {
}
}
}
Some("<anonymous>")
None
}

fn get_kind(node: &Node) -> NodeKind {
Expand All @@ -149,10 +145,6 @@ impl Getter for CCode {
}

impl Getter for CppCode {
fn get_func_name<'a>(node: &Node, code: &'a [u8]) -> Option<&'a str> {
Self::get_func_space_name(node, code)
}

fn get_func_space_name<'a>(node: &Node, code: &'a [u8]) -> Option<&'a str> {
let typ = node.kind_id();
match typ.into() {
Expand All @@ -166,7 +158,14 @@ impl Getter for CppCode {
}) {
if let Some(first) = fd.child(0) {
match first.kind_id().into() {
Cpp::ScopedIdentifier | Cpp::Identifier => {
Cpp::ScopedIdentifier
| Cpp::Identifier
| Cpp::FieldIdentifier
| Cpp::ScopedFieldIdentifier
| Cpp::DestructorName
| Cpp::OperatorName
| Cpp::TemplateFunction
| Cpp::TemplateMethod => {
let code = &code[first.start_byte()..first.end_byte()];
return std::str::from_utf8(code).ok();
}
Expand All @@ -183,8 +182,7 @@ impl Getter for CppCode {
}
}
}

Some("<anonymous>")
None
}

fn get_kind(node: &Node) -> NodeKind {
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ pub use crate::getter::*;
pub mod find;
pub use crate::find::*;

pub mod function;
pub use crate::function::*;

pub mod count;
pub use crate::count::*;

Expand Down
13 changes: 13 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct Config {
comments: bool,
find_filter: Vec<String>,
count_filter: Vec<String>,
function: bool,
metrics: bool,
line_start: Option<usize>,
line_end: Option<usize>,
Expand Down Expand Up @@ -87,6 +88,10 @@ fn act_on_file(language: LANG, path: PathBuf, cfg: Config) -> std::io::Result<()
} else {
action::<CommentRm>(&language, source, &cfg.path.clone(), pr, cfg)
}
} else if cfg.function {
let source = read_file_with_eol(&path)?;
let cfg = FunctionCfg { path: path.clone() };
action::<Function>(&language, source, &path, pr, cfg)
} else if !cfg.find_filter.is_empty() {
let source = read_file_with_eol(&path)?;
let cfg = FindCfg {
Expand Down Expand Up @@ -247,6 +252,12 @@ fn main() {
.default_value("")
.takes_value(true),
)
.arg(
Arg::with_name("function")
.help("Get functions and their spans")
.short("F")
.long("function"),
)
.arg(
Arg::with_name("count")
.help("Count nodes of the given type: comma separated list")
Expand Down Expand Up @@ -380,6 +391,7 @@ fn main() {
let paths: Vec<_> = matches.values_of("paths").unwrap().collect();
let paths: Vec<String> = paths.iter().map(|x| x.to_string()).collect();
let dump = matches.is_present("dump");
let function = matches.is_present("function");
let in_place = matches.is_present("in_place");
let comments = matches.is_present("remove_comments");
let find = matches.value_of("find").unwrap();
Expand Down Expand Up @@ -451,6 +463,7 @@ fn main() {
comments,
find_filter,
count_filter,
function,
metrics,
line_start,
line_end,
Expand Down
24 changes: 24 additions & 0 deletions src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,28 @@ impl<'a> Search<'a> for Node<'a> {

None
}

fn act_on_node(&self, action: &mut dyn FnMut(&Node<'a>)) {
let mut cursor = self.walk();
let mut stack = Vec::new();
let mut children = Vec::new();

stack.push(*self);

while let Some(node) = stack.pop() {
action(&node);
cursor.reset(node);
if cursor.goto_first_child() {
loop {
children.push(cursor.node());
if !cursor.goto_next_sibling() {
break;
}
}
for child in children.drain(..).rev() {
stack.push(child);
}
}
}
}
}
1 change: 1 addition & 0 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ pub trait Callback {

pub trait Search<'a> {
fn first_occurence(&self, pred: fn(u16) -> bool) -> Option<Node<'a>>;
fn act_on_node(&self, pred: &mut dyn FnMut(&Node<'a>));
}
39 changes: 39 additions & 0 deletions src/web/function.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use serde::{Deserialize, Serialize};
use serde_json::{self, Value};

use crate::function::{function, FunctionSpan};
use crate::traits::{Callback, TSParserTrait};

#[derive(Debug, Deserialize, Serialize)]
pub struct WebFunctionPayload {
pub id: String,
pub file_name: String,
pub code: String,
}

#[derive(Debug, Serialize)]
pub struct WebFunctionResponse {
pub id: String,
pub spans: Vec<FunctionSpan>,
}

#[derive(Debug, Deserialize)]
pub struct WebFunctionInfo {
pub file_name: String,
}

pub struct WebFunctionCallback {}

pub struct WebFunctionCfg {
pub id: String,
}

impl Callback for WebFunctionCallback {
type Res = Value;
type Cfg = WebFunctionCfg;

fn call<T: TSParserTrait>(cfg: Self::Cfg, parser: &T) -> Self::Res {
let spans = function(parser);
serde_json::to_value(WebFunctionResponse { id: cfg.id, spans }).unwrap()
}
}
1 change: 1 addition & 0 deletions src/web/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod alterator;
pub mod ast;
pub mod comment;
pub mod function;
pub mod metrics;
pub mod server;
Loading

0 comments on commit 2e789f8

Please sign in to comment.