Skip to main content

rust_code_analysis_code_split/
function.rs

1use std::io::Write;
2use std::path::PathBuf;
3
4use serde::Serialize;
5use termcolor::{Color, ColorChoice, StandardStream, StandardStreamLock};
6
7use crate::traits::*;
8
9use crate::checker::Checker;
10use crate::getter::Getter;
11
12use crate::tools::{color, intense_color};
13
14/// Function span data.
15#[derive(Debug, Serialize)]
16pub struct FunctionSpan {
17    /// The function name
18    pub name: String,
19    /// The first line of a function
20    pub start_line: usize,
21    /// The last line of a function
22    pub end_line: usize,
23    /// If `true`, an error is occurred in determining the span
24    /// of a function
25    pub error: bool,
26}
27
28/// Detects the span of each function in a code.
29///
30/// Returns a vector containing the [`FunctionSpan`] of each function
31///
32/// [`FunctionSpan`]: struct.FunctionSpan.html
33pub fn function<T: ParserTrait>(parser: &T) -> Vec<FunctionSpan> {
34    let root = parser.get_root();
35    let code = parser.get_code();
36    let mut spans = Vec::new();
37    root.act_on_node(&mut |n| {
38        if T::Checker::is_func(n) {
39            let start_line = n.start_row() + 1;
40            let end_line = n.end_row() + 1;
41            if let Some(name) = T::Getter::get_func_name(n, code) {
42                spans.push(FunctionSpan {
43                    name: name.to_string(),
44                    start_line,
45                    end_line,
46                    error: false,
47                });
48            } else {
49                spans.push(FunctionSpan {
50                    name: "".to_string(),
51                    start_line,
52                    end_line,
53                    error: true,
54                });
55            }
56        }
57    });
58
59    spans
60}
61
62fn dump_span(
63    span: FunctionSpan,
64    stdout: &mut StandardStreamLock,
65    last: bool,
66) -> std::io::Result<()> {
67    /*if !span.error {
68        return Ok(());
69    }*/
70
71    let pref = if last { "   `- " } else { "   |- " };
72
73    color(stdout, Color::Blue)?;
74    write!(stdout, "{pref}")?;
75
76    if span.error {
77        intense_color(stdout, Color::Red)?;
78        write!(stdout, "error: ")?;
79    } else {
80        intense_color(stdout, Color::Magenta)?;
81        write!(stdout, "{}: ", span.name)?;
82    }
83
84    color(stdout, Color::Green)?;
85    write!(stdout, "from line ")?;
86
87    color(stdout, Color::White)?;
88    write!(stdout, "{}", span.start_line)?;
89
90    color(stdout, Color::Green)?;
91    write!(stdout, " to line ")?;
92
93    color(stdout, Color::White)?;
94    writeln!(stdout, "{}.", span.end_line)
95}
96
97fn dump_spans(mut spans: Vec<FunctionSpan>, path: PathBuf) -> std::io::Result<()> {
98    if !spans.is_empty() {
99        let stdout = StandardStream::stdout(ColorChoice::Always);
100        let mut stdout = stdout.lock();
101
102        intense_color(&mut stdout, Color::Yellow)?;
103        writeln!(&mut stdout, "In file {}", path.to_str().unwrap_or("..."))?;
104
105        for span in spans.drain(..spans.len() - 1) {
106            dump_span(span, &mut stdout, false)?;
107        }
108        dump_span(spans.pop().unwrap(), &mut stdout, true)?;
109        color(&mut stdout, Color::White)?;
110    }
111    Ok(())
112}
113
114/// Configuration options for detecting the span of
115/// each function in a code.
116#[derive(Debug)]
117pub struct FunctionCfg {
118    /// Path to the file containing the code
119    pub path: PathBuf,
120}
121
122pub struct Function {
123    _guard: (),
124}
125
126impl Callback for Function {
127    type Res = std::io::Result<()>;
128    type Cfg = FunctionCfg;
129
130    fn call<T: ParserTrait>(cfg: Self::Cfg, parser: &T) -> Self::Res {
131        dump_spans(function(parser), cfg.path)
132    }
133}