From 0022a364e65ac73d264622df00a88aa3f583a715 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Fri, 30 Sep 2022 18:30:54 +0000 Subject: [PATCH 001/172] chore: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38cd90c0..dc3d0000 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ### Miscellaneous Tasks +- Update changelog - Update changelog - Update changelog From 4e81261b55a317cffaf07184074d14dbd3411cfe Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Fri, 30 Sep 2022 15:50:04 -0400 Subject: [PATCH 002/172] startedcwit python support no where ready a lot error - wont compilte masssive refactor required --- git-function-history-lib/Cargo.toml | 3 +- git-function-history-lib/src/languages/c.rs | 46 ++ git-function-history-lib/src/languages/mod.rs | 78 +++ .../src/languages/python.rs | 304 ++++++++++ .../src/languages/rust.rs | 546 ++++++++++++++++++ git-function-history-lib/src/lib.rs | 286 +-------- git-function-history-lib/src/types.rs | 405 ++----------- 7 files changed, 1030 insertions(+), 638 deletions(-) create mode 100644 git-function-history-lib/src/languages/c.rs create mode 100644 git-function-history-lib/src/languages/mod.rs create mode 100644 git-function-history-lib/src/languages/python.rs create mode 100644 git-function-history-lib/src/languages/rust.rs diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 417b24ef..65ac1748 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -15,4 +15,5 @@ parallel = ["dep:rayon"] [dependencies] chrono = "0.4.22" ra_ap_syntax = "0.0.131" -rayon = { version = "1.5.1", optional = true } \ No newline at end of file +rayon = { version = "1.5.1", optional = true } +rustpython-parser = "0.1.2" \ No newline at end of file diff --git a/git-function-history-lib/src/languages/c.rs b/git-function-history-lib/src/languages/c.rs new file mode 100644 index 00000000..15c0c2d5 --- /dev/null +++ b/git-function-history-lib/src/languages/c.rs @@ -0,0 +1,46 @@ +use std::collections::HashMap; + +pub struct Function { + name: String, + body: String, + // parameters: Params, + parameters: Vec, + parent: Vec, + returns: Option, +} + +impl Function { + pub fn new(name: String, body: String, parameters: Vec, parent: Vec, returns: Option) -> Self { + Self { + name, + body, + parameters, + parent, + returns, + } + } +} + +impl super::Function for Function { + fn fmt_with_context( + &self, + f: &mut std::fmt::Formatter<'_>, + previous: Option<&Self>, + next: Option<&Self>, + ) -> std::fmt::Result { + todo!() + } + + fn get_metadata(&self) -> HashMap<&str, String> { + todo!() + } +} + +pub struct ParentFunction { + name: String, + top: String, + bottom: String, + lines: (usize, usize), + parameters: Vec, + returns: Option, +} \ No newline at end of file diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs new file mode 100644 index 00000000..fbb7caac --- /dev/null +++ b/git-function-history-lib/src/languages/mod.rs @@ -0,0 +1,78 @@ +use std::{fmt, collections::HashMap, error::Error}; + +use crate::{File, Filter}; + +pub enum Language { + /// The python language + Python, + /// The rust language + Rust, + /// c language + C, +} + +pub mod c; +pub mod python; +pub mod rust; + + +// make macro that turns a language into its function struct +macro_rules! language { + ($name:ident, $struct:ident) => { + pub fn $name() -> Language { + Language::$struct + } + }; +} + +language!(python, Python); + +pub trait Function { + fn fmt_with_context( + &self, + f: &mut fmt::Formatter<'_>, + previous: Option<&Self>, + next: Option<&Self>, + ) -> fmt::Result; + fn get_metadata(&self) -> HashMap<&str, String>; +} + +impl File { + pub fn filter_by(&self, filter: &Filter) -> Result> { + let mut vec = Vec::new(); + for function in &self.functions { + match &filter { + Filter::FunctionInBlock(block_type) => { + if let Some(block) = &function.block { + if block.block_type == *block_type { + vec.push(function.clone()); + } + } + } + Filter::FunctionInLines(start, end) => { + if function.lines.0 >= *start && function.lines.1 <= *end { + vec.push(function.clone()); + } + } + Filter::FunctionWithParent(parent) => { + for parents in &function.function { + if parents.name == *parent { + vec.push(function.clone()); + } + } + } + Filter::None => vec.push(function.clone()), + _ => return Err("Filter not available")?, + } + } + if vec.is_empty() { + return Err("No functions found for filter")?; + } + Ok(Self { + name: self.name.clone(), + functions: vec, + current_pos: 0, + }) + } +} + diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs new file mode 100644 index 00000000..d8e2ee94 --- /dev/null +++ b/git-function-history-lib/src/languages/python.rs @@ -0,0 +1,304 @@ +use std::{error::Error, collections::HashMap}; + +use rustpython_parser::{location::Location, ast::{StatementType, Located}, parser}; + +use crate::File; + +pub struct Function { + name: String, + body: String, + // parameters: Params, + parameters: Vec, + parent: Vec, + decorators: Vec, + class: Option, + returns: Option, +} + +impl Function { + +} + +impl super::Function for Function { + fn fmt_with_context( + &self, + f: &mut std::fmt::Formatter<'_>, + previous: Option<&Self>, + next: Option<&Self>, + ) -> std::fmt::Result { + todo!() + } + + fn get_metadata(&self) -> HashMap<&str, String> { + todo!() + } +} + +pub struct Params { + args: Vec, + kwargs: Vec, + varargs: Option, + varkwargs: Option, +} + +pub struct Class { + name: String, + top: String, + bottom: String, + lines: (usize, usize), + decorators: Vec, +} + +pub struct ParentFunction { + name: String, + top: String, + bottom: String, + lines: (usize, usize), + parameters: Vec, + decorators: Vec, + class: Option, + returns: Option, +} + +pub fn get_file_in_commit( + commit: &str, + file_path: &str, + name: &str, +) -> Result, Box> { + let file_contents = crate::find_file_in_commit(commit, file_path)?; + let ast = parser::parse_program(&file_contents)?; + let mut functions = vec![]; + let mut last = None; + for stmt in ast.statements { + get_functions(stmt, &mut functions, "baz", &mut last, &mut None); + } + let mut starts = file_contents + .match_indices('\n') + .map(|x| x.0) + .collect::>(); + starts.push(0); + starts.sort_unstable(); + let map = starts + .iter() + .enumerate() + .collect::>(); + let mut new = Vec::new(); + for func in functions { + // get the function body based on the location + let start = func.1 .0.row(); + let end = func.1 .1.row(); + let start = map[&(start - 1)]; + let end = map[&(end - 1)]; + if let StatementType::FunctionDef { + name, + args, + decorator_list, + returns, + is_async: _, + .. + } = func.0 + { + let body = file_contents[*start..*end].to_string(); + let new_func = Function { + name: name.to_string(), + returns: returns.as_ref().map(|x| x.name().to_string()), + parameters: args.args.iter().map(|x| x.arg.to_string()).collect(), + parent: vec![], + decorators: decorator_list + .iter() + .map(|x| x.name().to_string()) + .collect(), + class: None, + body, + }; + new.push(new_func); + } + } + Ok(File::new(name.to_string(), new)) +} + +fn fun_name1( + body: Vec>, + functions: &mut Vec<(StatementType, (Location, Location))>, + lookup_name: &str, + last_found_fn: &mut Option<(StatementType, Location)>, + other_last_found_fn: &mut Option<(StatementType, Location)>, +) { + for stmt in body { + get_functions( + stmt, + functions, + lookup_name, + last_found_fn, + other_last_found_fn, + ); + } +} + +fn fun_name( + other_last_found_fn: &mut Option<(StatementType, Location)>, + last_found_fn: &mut Option<(StatementType, Location)>, + functions: &mut Vec<(StatementType, (Location, Location))>, + stmt: Location, +) { + std::mem::swap(other_last_found_fn, last_found_fn); + let mut other = None; + std::mem::swap(&mut other, other_last_found_fn); + if let Some(body) = other { + functions.push((body.0, (body.1, stmt))); + } +} + +fn get_functions<'a>( + stmt: Located, + functions: &mut Vec<(StatementType, (Location, Location))>, + lookup_name: &str, + last_found_fn: &'a mut Option<(StatementType, Location)>, + other_last_found_fn: &'a mut Option<(StatementType, Location)>, +) { + match stmt.node { + StatementType::FunctionDef { ref name, .. } if name == lookup_name => { + if let Some(ref mut last) = last_found_fn { + let mut new = (stmt.node, stmt.location); + std::mem::swap(last, &mut new); + functions.push((new.0, (new.1, stmt.location))); + } else { + *last_found_fn = Some((stmt.node, stmt.location)); + } + } + StatementType::FunctionDef { body, .. } => { + fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); + fun_name1( + body, + functions, + lookup_name, + last_found_fn, + other_last_found_fn, + ); + } + StatementType::If { body, orelse, .. } => { + fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); + fun_name1( + body, + functions, + lookup_name, + last_found_fn, + other_last_found_fn, + ); + + if let Some(stmts) = orelse { + fun_name1( + stmts, + functions, + lookup_name, + last_found_fn, + other_last_found_fn, + ); + } + } + StatementType::While { body, orelse, .. } => { + fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); + fun_name1( + body, + functions, + lookup_name, + last_found_fn, + other_last_found_fn, + ); + if let Some(stmts) = orelse { + fun_name1( + stmts, + functions, + lookup_name, + last_found_fn, + other_last_found_fn, + ); + } + } + StatementType::For { body, orelse, .. } => { + fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); + fun_name1( + body, + functions, + lookup_name, + last_found_fn, + other_last_found_fn, + ); + if let Some(stmts) = orelse { + fun_name1( + stmts, + functions, + lookup_name, + last_found_fn, + other_last_found_fn, + ); + } + } + StatementType::With { body, .. } => { + fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); + fun_name1( + body, + functions, + lookup_name, + last_found_fn, + other_last_found_fn, + ); + } + StatementType::Try { + body, + handlers, + orelse, + finalbody, + } => { + fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); + fun_name1( + body, + functions, + lookup_name, + last_found_fn, + other_last_found_fn, + ); + for handler in handlers { + fun_name1( + handler.body, + functions, + lookup_name, + last_found_fn, + other_last_found_fn, + ); + } + + if let Some(stmts) = orelse { + fun_name1( + stmts, + functions, + lookup_name, + last_found_fn, + other_last_found_fn, + ); + } + if let Some(stmts) = finalbody { + fun_name1( + stmts, + functions, + lookup_name, + last_found_fn, + other_last_found_fn, + ); + } + } + StatementType::ClassDef { body, .. } => { + fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); + fun_name1( + body, + functions, + lookup_name, + last_found_fn, + other_last_found_fn, + ); + } + _ => { + fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); + } + } +} diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs new file mode 100644 index 00000000..852ba60d --- /dev/null +++ b/git-function-history-lib/src/languages/rust.rs @@ -0,0 +1,546 @@ +use std::{collections::HashMap, fmt, error::Error}; + +use ra_ap_syntax::{ + ast::{self, HasDocComments, HasGenericParams, HasName}, + AstNode, SourceFile, SyntaxKind, +}; + +/// This holds the information about a single function each commit will have multiple of these. +#[derive(Debug, Clone)] +pub struct Function { + pub(crate) name: String, + /// The actual code of the function + pub(crate) contents: String, + /// is the function in a block ie `impl` `trait` etc + pub(crate) block: Option, + /// optional parent functions + pub(crate) function: Vec, + /// The line number the function starts and ends on + pub(crate) lines: (usize, usize), + /// The lifetime of the function + pub(crate) lifetime: Vec, + /// The generic types of the function + pub(crate) generics: Vec, + /// The arguments of the function + pub(crate) arguments: Vec, + /// The return type of the function + pub(crate) return_type: Option, + /// The functions atrributes + pub(crate) attributes: Vec, + /// the functions doc comments + pub(crate) doc_comments: Vec, +} + +impl super::Function for Function { + /// This is a formater almost like the fmt you use for println!, but it takes a previous and next function. + /// This is usefull for printing `CommitHistory` or a vector of functions, because if you use plain old fmt, you can get repeated lines impls, and parent function in your output. + fn fmt_with_context( + &self, + f: &mut fmt::Formatter<'_>, + previous: Option<&Self>, + next: Option<&Self>, + ) -> fmt::Result { + match &self.block { + None => {} + Some(block) => match previous { + None => write!(f, "{}\n...\n", block.top)?, + Some(previous_function) => match &previous_function.block { + None => write!(f, "{}\n...\n", block.top)?, + Some(previous_block) => { + if previous_block.lines == block.lines { + } else { + write!(f, "{}\n...\n", block.top)?; + } + } + }, + }, + }; + if !self.function.is_empty() { + for i in &self.function { + match previous { + None => write!(f, "{}\n...\n", i.top)?, + Some(previous_function) => { + if previous_function + .function + .iter() + .any(|x| x.lines == i.lines) + { + } else { + write!(f, "{}\n...\n", i.top)?; + } + } + }; + } + } + + write!(f, "{}", self.contents)?; + if !self.function.is_empty() { + for i in &self.function { + match next { + None => write!(f, "\n...{}", i.bottom)?, + Some(next_function) => { + if next_function.function.iter().any(|x| x.lines == i.lines) { + } else { + write!(f, "\n...{}", i.bottom)?; + } + } + }; + } + } + match &self.block { + None => {} + Some(block) => match next { + None => write!(f, "\n...{}", block.bottom)?, + Some(next_function) => match &next_function.block { + None => write!(f, "\n...{}", block.bottom)?, + Some(next_block) => { + if next_block.lines == block.lines { + } else { + write!(f, "\n...{}", block.bottom)?; + } + } + }, + }, + }; + Ok(()) + } + + /// get metadata like line number, number of parent function etc. + fn get_metadata(&self) -> HashMap<&str, String> { + let mut map = HashMap::new(); + map.insert("name", self.name.clone()); + map.insert("lines", format!("{:?}", self.lines)); + map.insert("contents", self.contents.clone()); + if let Some(block) = &self.block { + map.insert("block", format!("{}", block.block_type)); + } + map.insert("generics", self.generics.join(",")); + map.insert("arguments", self.arguments.join(",")); + map.insert("lifetime generics", self.lifetime.join(",")); + map.insert("attributes", self.attributes.join(",")); + map.insert("doc comments", self.doc_comments.join(",")); + match &self.return_type { + None => {} + Some(return_type) => { + map.insert("return type", return_type.clone()); + } + }; + map + } + + +} + +impl Function { + /// get the parent functions + pub fn get_parent_function(&self) -> Vec { + self.function.clone() + } + + /// get the block of the function + pub fn get_block(&self) -> Option { + self.block.clone() + } + +} + +impl fmt::Display for Function { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.block { + None => {} + Some(block) => write!(f, "{}\n...\n", block.top)?, + }; + for i in &self.function { + write!(f, "{}\n...\n", i.top)?; + } + write!(f, "{}", self.contents)?; + for i in &self.function { + write!(f, "\n...\n{}", i.bottom)?; + } + match &self.block { + None => {} + Some(block) => write!(f, "\n...{}", block.bottom)?, + }; + Ok(()) + } +} + +/// This is used for the functions that are being looked up themeselves but store an outer function that may aontains a function that is being looked up. +#[derive(Debug, Clone)] +pub struct FunctionBlock { + /// The name of the function (parent function) + pub(crate) name: String, + /// what the signature of the function is + pub(crate) top: String, + /// what the last line of the function is + pub(crate) bottom: String, + /// The line number the function starts and ends on + pub(crate) lines: (usize, usize), + /// The lifetime of the function + pub(crate) lifetime: Vec, + /// The generic types of the function + pub(crate) generics: Vec, + /// The arguments of the function + pub(crate) arguments: Vec, + /// The return type of the function + pub(crate) return_type: Option, + /// the function atrributes + pub(crate) attributes: Vec, + /// the functions doc comments + pub(crate) doc_comments: Vec, +} + +impl FunctionBlock { + /// get the metadata for this block ie the name of the block, the type of block, the line number the block starts and ends + pub fn get_metadata(&self) -> HashMap { + let mut map = HashMap::new(); + map.insert("name".to_string(), self.name.clone()); + map.insert("lines".to_string(), format!("{:?}", self.lines)); + map.insert("signature".to_string(), self.top.clone()); + map.insert("bottom".to_string(), self.bottom.clone()); + map.insert("generics".to_string(), self.generics.join(",")); + map.insert("arguments".to_string(), self.arguments.join(",")); + map.insert("lifetime generics".to_string(), self.lifetime.join(",")); + map.insert("attributes".to_string(), self.attributes.join(",")); + map.insert("doc comments".to_string(), self.doc_comments.join(",")); + match &self.return_type { + None => {} + Some(return_type) => { + map.insert("return type".to_string(), return_type.clone()); + } + }; + map + } +} + +/// This holds information about when a function is in an impl/trait/extern block +#[derive(Debug, Clone)] +pub struct Block { + /// The name of the block ie for `impl` it would be the type were impling for + pub(crate) name: Option, + /// The signature of the block + pub(crate) top: String, + /// The last line of the block + pub(crate) bottom: String, + /// the type of block ie `impl` `trait` `extern` + pub(crate) block_type: BlockType, + /// The line number the function starts and ends on + pub(crate) lines: (usize, usize), + /// The lifetime of the function + pub(crate) lifetime: Vec, + /// The generic types of the function + pub(crate) generics: Vec, + /// The blocks atrributes + pub(crate) attributes: Vec, + /// the blocks doc comments + pub(crate) doc_comments: Vec, +} + +impl Block { + /// get the metadata for this block ie the name of the block, the type of block, the line number the block starts and ends + pub fn get_metadata(&self) -> HashMap { + let mut map = HashMap::new(); + if let Some(name) = &self.name { + map.insert("name".to_string(), name.to_string()); + } + map.insert("block".to_string(), format!("{}", self.block_type)); + map.insert("lines".to_string(), format!("{:?}", self.lines)); + map.insert("signature".to_string(), self.top.clone()); + map.insert("bottom".to_string(), self.bottom.clone()); + map.insert("generics".to_string(), self.generics.join(",")); + map.insert("lifetime generics".to_string(), self.lifetime.join(",")); + map.insert("attributes".to_string(), self.attributes.join(",")); + map.insert("doc comments".to_string(), self.doc_comments.join(",")); + map + } +} + +/// This enum is used when filtering commit history only for let say impl and not externs or traits +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum BlockType { + /// This is for `impl` blocks + Impl, + /// This is for `trait` blocks + Extern, + /// This is for `extern` blocks + Trait, + /// This is for code that gets labeled as a block but `get_function_history` can't find a block type + Unknown, +} + +impl BlockType { + /// This is used to get the name of the block type from a string + pub fn from_string(s: &str) -> Self { + match s { + "impl" => Self::Impl, + "extern" => Self::Extern, + "trait" => Self::Trait, + _ => Self::Unknown, + } + } +} + +impl fmt::Display for BlockType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Impl => write!(f, "impl"), + Self::Extern => write!(f, "extern"), + Self::Trait => write!(f, "trait"), + Self::Unknown => write!(f, "unknown"), + } + } +} + +#[allow(clippy::too_many_lines)] +// TODO: split this function into smaller functions +fn find_function_in_commit( + commit: &str, + file_path: &str, + name: &str, +) -> Result, Box> { + let file_contents = crate::find_file_in_commit(commit, file_path)?; + let mut functions = Vec::new(); + get_function_asts(name, &file_contents, &mut functions); + let mut starts = file_contents + .match_indices('\n') + .map(|x| x.0) + .collect::>(); + starts.push(0); + starts.sort_unstable(); + let map = starts + .iter() + .enumerate() + .collect::>(); + let mut hist = Vec::new(); + for f in &functions { + let stuff = get_stuff(f, &file_contents, &map); + let generics = get_genrerics_and_lifetime(f); + let mut parent = f.syntax().parent(); + let mut parent_fn: Vec = Vec::new(); + let mut parent_block = None; + while let Some(p) = parent.into_iter().next() { + if p.kind() == SyntaxKind::SOURCE_FILE { + break; + } + ast::Fn::cast(p.clone()).map_or_else( + || { + if let Some(block) = ast::Impl::cast(p.clone()) { + let attr = get_doc_comments_and_attrs(&block); + let stuff = get_stuff(&block, &file_contents, &map); + let generics = get_genrerics_and_lifetime(&block); + parent_block = Some(Block { + name: block.self_ty().map(|ty| ty.to_string()), + lifetime: generics.1, + generics: generics.0, + top: stuff.1 .0, + bottom: stuff.1 .1, + block_type: BlockType::Impl, + lines: (stuff.0 .0, stuff.0 .1), + attributes: attr.1, + doc_comments: attr.0, + }); + } else if let Some(block) = ast::Trait::cast(p.clone()) { + let attr = get_doc_comments_and_attrs(&block); + let stuff = get_stuff(&block, &file_contents, &map); + let generics = get_genrerics_and_lifetime(&block); + parent_block = Some(Block { + name: block.name().map(|ty| ty.to_string()), + lifetime: generics.1, + generics: generics.0, + top: stuff.1 .0, + bottom: stuff.1 .1, + block_type: BlockType::Trait, + lines: (stuff.0 .0, stuff.0 .1), + attributes: attr.1, + doc_comments: attr.0, + }); + } else if let Some(block) = ast::ExternBlock::cast(p.clone()) { + let attr = get_doc_comments_and_attrs(&block); + let stuff = get_stuff(&block, &file_contents, &map); + parent_block = Some(Block { + name: block.abi().map(|ty| ty.to_string()), + lifetime: Vec::new(), + generics: Vec::new(), + top: stuff.1 .0, + bottom: stuff.1 .1, + block_type: BlockType::Extern, + lines: (stuff.0 .0, stuff.0 .1), + attributes: attr.1, + doc_comments: attr.0, + }); + } + }, + |function| { + let stuff = get_stuff(&function, &file_contents, &map); + let generics = get_genrerics_and_lifetime(&function); + let attr = get_doc_comments_and_attrs(&function); + parent_fn.push(FunctionBlock { + name: function.name().unwrap().to_string(), + lifetime: generics.1, + generics: generics.0, + top: stuff.1 .0, + bottom: stuff.1 .1, + lines: (stuff.0 .0, stuff.0 .1), + return_type: function.ret_type().map(|ty| ty.to_string()), + arguments: match function.param_list() { + Some(args) => args + .params() + .map(|arg| arg.to_string()) + .collect::>(), + None => Vec::new(), + }, + attributes: attr.1, + doc_comments: attr.0, + }); + }, + ); + parent = p.parent(); + } + let attr = get_doc_comments_and_attrs(f); + let mut start = stuff.0 .0; + let bb = match map[&start] { + 0 => 0, + x => x + 1, + }; + let contents: String = file_contents[bb..f.syntax().text_range().end().into()] + .to_string() + .lines() + .map(|l| { + start += 1; + format!("{}: {}\n", start, l,) + }) + .collect(); + let contents = contents.trim_end().to_string(); + let function = Function { + name: f.name().unwrap().to_string(), + contents, + block: parent_block, + function: parent_fn, + return_type: f.ret_type().map(|ty| ty.to_string()), + arguments: match f.param_list() { + Some(args) => args + .params() + .map(|arg| arg.to_string()) + .collect::>(), + None => Vec::new(), + }, + lifetime: generics.1, + generics: generics.0, + lines: (stuff.0 .0, stuff.0 .1), + attributes: attr.1, + doc_comments: attr.0, + }; + hist.push(function); + } + if hist.is_empty() { + Err("no function found")?; + } + Ok(hist) +} + +fn get_function_asts(name: &str, file: &str, functions: &mut Vec) { + let parsed_file = SourceFile::parse(file).tree(); + parsed_file + .syntax() + .descendants() + .filter_map(ast::Fn::cast) + .filter(|function| function.name().unwrap().text() == name) + .for_each(|function| functions.push(function)); +} + +fn get_stuff( + block: &T, + file: &str, + map: &HashMap, +) -> ((usize, usize), (String, String), (usize, usize)) { + let start = block.syntax().text_range().start(); + let end = block.syntax().text_range().end(); + // get the start and end lines + let mut found_start_brace = 0; + let mut end_line = 0; + let mut starts = 0; + let mut start_line = 0; + // TODO: combine these loops + for (i, line) in file.chars().enumerate() { + if line == '\n' { + if usize::from(start) < i { + starts = i; + break; + } + start_line += 1; + } + } + for (i, line) in file.chars().enumerate() { + if line == '\n' { + if usize::from(end) < i { + break; + } + end_line += 1; + } + if line == '{' && found_start_brace == 0 && usize::from(start) < i { + found_start_brace = i; + } + } + if found_start_brace == 0 { + found_start_brace = usize::from(start); + } + let start = map[&start_line]; + let mut start_lines = start_line; + let mut content: String = file[(*start)..=found_start_brace].to_string(); + if &content[..1] == "\n" { + content = content[1..].to_string(); + } + ( + (start_line, end_line), + ( + content + .lines() + .map(|l| { + start_lines += 1; + format!("{}: {}\n", start_lines, l,) + }) + .collect::() + .trim_end() + .to_string(), + format!( + "\n{}: {}", + end_line, + file.lines() + .nth(if end_line == file.lines().count() - 1 { + end_line + } else { + end_line - 1 + }) + .unwrap_or("") + ), + ), + (starts, end_line), + ) +} + +fn get_genrerics_and_lifetime(block: &T) -> (Vec, Vec) { + match block.generic_param_list() { + None => (vec![], vec![]), + Some(gt) => ( + gt.generic_params() + .map(|gt| gt.to_string()) + .collect::>(), + gt.lifetime_params() + .map(|lt| lt.to_string()) + .collect::>(), + ), + } +} + +fn get_doc_comments_and_attrs(block: &T) -> (Vec, Vec) { + ( + block + .doc_comments() + .map(|c| c.to_string()) + .collect::>(), + block + .attrs() + .map(|c| c.to_string()) + .collect::>(), + ) +} diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index b42547ea..f11bbd2f 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -14,18 +14,16 @@ clippy::return_self_not_must_use )] +pub mod languages; /// Different types that can extracted from the result of `get_function_history`. pub mod types; -use ra_ap_syntax::{ - ast::{self, HasDocComments, HasGenericParams, HasName}, - AstNode, SourceFile, SyntaxKind, -}; + #[cfg(feature = "parallel")] use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; -use std::{collections::HashMap, error::Error, process::Command}; +use std::{error::Error, process::Command}; pub use types::{ - Block, BlockType, CommitFunctions, File, Function, FunctionBlock, FunctionHistory, + CommitFunctions, File, FunctionHistory }; /// Different filetypes that can be used to ease the process of finding functions using `get_function_history`. @@ -44,7 +42,7 @@ pub enum FileType { // TODO: Add support for filtering by generic parameters, lifetimes, and return types. /// This is filter enum is used when you want to lookup a function with the filter of filter a previous lookup. #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Filter { +pub enum Filter { /// When you want to filter by a commit hash. CommitHash(String), /// When you want to filter by a specific date (in rfc2822 format). @@ -58,7 +56,7 @@ pub enum Filter { /// When you want to filter only files in a specific directory Directory(String), // when you want to filter by function that are in a specific block (impl, trait, extern) - FunctionInBlock(BlockType), + FunctionInBlock(Block), // when you want to filter by function that are in between specific lines FunctionInLines(usize, usize), // when you want filter by a function that has a parent function of a specific name @@ -104,11 +102,12 @@ pub enum Filter { /// ``` #[allow(clippy::too_many_lines)] // TODO: split this function into smaller functions -pub fn get_function_history( +pub fn get_function_history( name: &str, file: &FileType, - filter: Filter, -) -> Result> { + filter: Filter, + languages: &[languages::Language], +) -> Result, Box> { // chack if name is empty if name.is_empty() { Err("function name is empty")?; @@ -277,265 +276,12 @@ fn find_file_in_commit(commit: &str, file_path: &str) -> Result Result, Box> { - let file_contents = find_file_in_commit(commit, file_path)?; - let mut functions = Vec::new(); - get_function_asts(name, &file_contents, &mut functions); - let mut starts = file_contents - .match_indices('\n') - .map(|x| x.0) - .collect::>(); - starts.push(0); - starts.sort_unstable(); - let map = starts - .iter() - .enumerate() - .collect::>(); - let mut hist = Vec::new(); - for f in &functions { - let stuff = get_stuff(f, &file_contents, &map); - let generics = get_genrerics_and_lifetime(f); - let mut parent = f.syntax().parent(); - let mut parent_fn: Vec = Vec::new(); - let mut parent_block = None; - while let Some(p) = parent.into_iter().next() { - if p.kind() == SyntaxKind::SOURCE_FILE { - break; - } - ast::Fn::cast(p.clone()).map_or_else( - || { - if let Some(block) = ast::Impl::cast(p.clone()) { - let attr = get_doc_comments_and_attrs(&block); - let stuff = get_stuff(&block, &file_contents, &map); - let generics = get_genrerics_and_lifetime(&block); - parent_block = Some(Block { - name: block.self_ty().map(|ty| ty.to_string()), - lifetime: generics.1, - generics: generics.0, - top: stuff.1 .0, - bottom: stuff.1 .1, - block_type: BlockType::Impl, - lines: (stuff.0 .0, stuff.0 .1), - attributes: attr.1, - doc_comments: attr.0, - }); - } else if let Some(block) = ast::Trait::cast(p.clone()) { - let attr = get_doc_comments_and_attrs(&block); - let stuff = get_stuff(&block, &file_contents, &map); - let generics = get_genrerics_and_lifetime(&block); - parent_block = Some(Block { - name: block.name().map(|ty| ty.to_string()), - lifetime: generics.1, - generics: generics.0, - top: stuff.1 .0, - bottom: stuff.1 .1, - block_type: BlockType::Trait, - lines: (stuff.0 .0, stuff.0 .1), - attributes: attr.1, - doc_comments: attr.0, - }); - } else if let Some(block) = ast::ExternBlock::cast(p.clone()) { - let attr = get_doc_comments_and_attrs(&block); - let stuff = get_stuff(&block, &file_contents, &map); - parent_block = Some(Block { - name: block.abi().map(|ty| ty.to_string()), - lifetime: Vec::new(), - generics: Vec::new(), - top: stuff.1 .0, - bottom: stuff.1 .1, - block_type: BlockType::Extern, - lines: (stuff.0 .0, stuff.0 .1), - attributes: attr.1, - doc_comments: attr.0, - }); - } - }, - |function| { - let stuff = get_stuff(&function, &file_contents, &map); - let generics = get_genrerics_and_lifetime(&function); - let attr = get_doc_comments_and_attrs(&function); - parent_fn.push(FunctionBlock { - name: function.name().unwrap().to_string(), - lifetime: generics.1, - generics: generics.0, - top: stuff.1 .0, - bottom: stuff.1 .1, - lines: (stuff.0 .0, stuff.0 .1), - return_type: function.ret_type().map(|ty| ty.to_string()), - arguments: match function.param_list() { - Some(args) => args - .params() - .map(|arg| arg.to_string()) - .collect::>(), - None => Vec::new(), - }, - attributes: attr.1, - doc_comments: attr.0, - }); - }, - ); - parent = p.parent(); - } - let attr = get_doc_comments_and_attrs(f); - let mut start = stuff.0 .0; - let bb = match map[&start] { - 0 => 0, - x => x + 1, - }; - let contents: String = file_contents[bb..f.syntax().text_range().end().into()] - .to_string() - .lines() - .map(|l| { - start += 1; - format!("{}: {}\n", start, l,) - }) - .collect(); - let contents = contents.trim_end().to_string(); - let function = Function { - name: f.name().unwrap().to_string(), - contents, - block: parent_block, - function: parent_fn, - return_type: f.ret_type().map(|ty| ty.to_string()), - arguments: match f.param_list() { - Some(args) => args - .params() - .map(|arg| arg.to_string()) - .collect::>(), - None => Vec::new(), - }, - lifetime: generics.1, - generics: generics.0, - lines: (stuff.0 .0, stuff.0 .1), - attributes: attr.1, - doc_comments: attr.0, - }; - hist.push(function); - } - if hist.is_empty() { - Err("no function found")?; - } - Ok(hist) -} - -fn get_function_asts(name: &str, file: &str, functions: &mut Vec) { - let parsed_file = SourceFile::parse(file).tree(); - parsed_file - .syntax() - .descendants() - .filter_map(ast::Fn::cast) - .filter(|function| function.name().unwrap().text() == name) - .for_each(|function| functions.push(function)); -} - -fn get_stuff( - block: &T, - file: &str, - map: &HashMap, -) -> ((usize, usize), (String, String), (usize, usize)) { - let start = block.syntax().text_range().start(); - let end = block.syntax().text_range().end(); - // get the start and end lines - let mut found_start_brace = 0; - let mut end_line = 0; - let mut starts = 0; - let mut start_line = 0; - // TODO: combine these loops - for (i, line) in file.chars().enumerate() { - if line == '\n' { - if usize::from(start) < i { - starts = i; - break; - } - start_line += 1; - } - } - for (i, line) in file.chars().enumerate() { - if line == '\n' { - if usize::from(end) < i { - break; - } - end_line += 1; - } - if line == '{' && found_start_brace == 0 && usize::from(start) < i { - found_start_brace = i; - } - } - if found_start_brace == 0 { - found_start_brace = usize::from(start); - } - let start = map[&start_line]; - let mut start_lines = start_line; - let mut content: String = file[(*start)..=found_start_brace].to_string(); - if &content[..1] == "\n" { - content = content[1..].to_string(); - } - ( - (start_line, end_line), - ( - content - .lines() - .map(|l| { - start_lines += 1; - format!("{}: {}\n", start_lines, l,) - }) - .collect::() - .trim_end() - .to_string(), - format!( - "\n{}: {}", - end_line, - file.lines() - .nth(if end_line == file.lines().count() - 1 { - end_line - } else { - end_line - 1 - }) - .unwrap_or("") - ), - ), - (starts, end_line), - ) -} - -fn get_genrerics_and_lifetime(block: &T) -> (Vec, Vec) { - match block.generic_param_list() { - None => (vec![], vec![]), - Some(gt) => ( - gt.generic_params() - .map(|gt| gt.to_string()) - .collect::>(), - gt.lifetime_params() - .map(|lt| lt.to_string()) - .collect::>(), - ), - } -} - -fn get_doc_comments_and_attrs(block: &T) -> (Vec, Vec) { - ( - block - .doc_comments() - .map(|c| c.to_string()) - .collect::>(), - block - .attrs() - .map(|c| c.to_string()) - .collect::>(), - ) -} -fn find_function_in_commit_with_filetype( +fn find_function_in_commit_with_filetype( commit: &str, name: &str, filetype: &FileType, -) -> Result, Box> { +) -> Result>, Box> { // get a list of all the files in the repository let mut files = Vec::new(); let command = Command::new("git") @@ -607,6 +353,7 @@ mod tests { "empty_test", &FileType::Relative("src/test_functions.rs".to_string()), Filter::None, + languages::Language::Rust, ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); @@ -624,6 +371,7 @@ mod tests { "empty_test", &FileType::Absolute("src/test_functions.rs".to_string()), Filter::None, + languages::Language::Rust, ); // assert that err is "not git is not installed" if output.is_err() { @@ -637,6 +385,7 @@ mod tests { "Not_a_function", &FileType::Absolute("src/test_functions.rs".to_string()), Filter::None, + languages::Language::Rust, ); match &output { Ok(output) => println!("{}", output), @@ -651,6 +400,7 @@ mod tests { "empty_test", &FileType::Absolute("src/test_functions.txt".to_string()), Filter::None, + languages::Language::Rust, ); assert!(output.is_err()); assert_eq!(output.unwrap_err().to_string(), "file is not a rust file"); @@ -665,6 +415,7 @@ mod tests { "17 Aug 2022 11:27:23 -0400".to_owned(), "19 Aug 2022 23:45:52 +0000".to_owned(), ), + languages::Language::Rust, ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); @@ -680,7 +431,8 @@ mod tests { #[test] fn expensive_tes() { let now = Utc::now(); - let output = get_function_history("empty_test", &FileType::None, Filter::None); + let output = get_function_history("empty_test", &FileType::None, Filter::None + , languages::Language::Rust); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); match &output { diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index cf970b9f..dff4602d 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -5,299 +5,18 @@ use std::{collections::HashMap, error::Error, fmt}; use crate::Filter; -/// This holds the information about a single function each commit will have multiple of these. -#[derive(Debug, Clone)] -pub struct Function { - pub(crate) name: String, - /// The actual code of the function - pub(crate) contents: String, - /// is the function in a block ie `impl` `trait` etc - pub(crate) block: Option, - /// optional parent functions - pub(crate) function: Vec, - /// The line number the function starts and ends on - pub(crate) lines: (usize, usize), - /// The lifetime of the function - pub(crate) lifetime: Vec, - /// The generic types of the function - pub(crate) generics: Vec, - /// The arguments of the function - pub(crate) arguments: Vec, - /// The return type of the function - pub(crate) return_type: Option, - /// The functions atrributes - pub(crate) attributes: Vec, - /// the functions doc comments - pub(crate) doc_comments: Vec, -} - -impl Function { - /// This is a formater almost like the fmt you use for println!, but it takes a previous and next function. - /// This is usefull for printing `CommitHistory` or a vector of functions, because if you use plain old fmt, you can get repeated lines impls, and parent function in your output. - pub fn fmt_with_context( - &self, - f: &mut fmt::Formatter<'_>, - previous: Option<&Self>, - next: Option<&Self>, - ) -> fmt::Result { - match &self.block { - None => {} - Some(block) => match previous { - None => write!(f, "{}\n...\n", block.top)?, - Some(previous_function) => match &previous_function.block { - None => write!(f, "{}\n...\n", block.top)?, - Some(previous_block) => { - if previous_block.lines == block.lines { - } else { - write!(f, "{}\n...\n", block.top)?; - } - } - }, - }, - }; - if !self.function.is_empty() { - for i in &self.function { - match previous { - None => write!(f, "{}\n...\n", i.top)?, - Some(previous_function) => { - if previous_function - .function - .iter() - .any(|x| x.lines == i.lines) - { - } else { - write!(f, "{}\n...\n", i.top)?; - } - } - }; - } - } - - write!(f, "{}", self.contents)?; - if !self.function.is_empty() { - for i in &self.function { - match next { - None => write!(f, "\n...{}", i.bottom)?, - Some(next_function) => { - if next_function.function.iter().any(|x| x.lines == i.lines) { - } else { - write!(f, "\n...{}", i.bottom)?; - } - } - }; - } - } - match &self.block { - None => {} - Some(block) => match next { - None => write!(f, "\n...{}", block.bottom)?, - Some(next_function) => match &next_function.block { - None => write!(f, "\n...{}", block.bottom)?, - Some(next_block) => { - if next_block.lines == block.lines { - } else { - write!(f, "\n...{}", block.bottom)?; - } - } - }, - }, - }; - Ok(()) - } - - /// get metadata like line number, number of parent function etc. - pub fn get_metadata(&self) -> HashMap<&str, String> { - let mut map = HashMap::new(); - map.insert("name", self.name.clone()); - map.insert("lines", format!("{:?}", self.lines)); - map.insert("contents", self.contents.clone()); - if let Some(block) = &self.block { - map.insert("block", format!("{}", block.block_type)); - } - map.insert("generics", self.generics.join(",")); - map.insert("arguments", self.arguments.join(",")); - map.insert("lifetime generics", self.lifetime.join(",")); - map.insert("attributes", self.attributes.join(",")); - map.insert("doc comments", self.doc_comments.join(",")); - match &self.return_type { - None => {} - Some(return_type) => { - map.insert("return type", return_type.clone()); - } - }; - map - } - - /// get the parent functions - pub fn get_parent_function(&self) -> Vec { - self.function.clone() - } - - /// get the block of the function - pub fn get_block(&self) -> Option { - self.block.clone() - } -} - -impl fmt::Display for Function { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self.block { - None => {} - Some(block) => write!(f, "{}\n...\n", block.top)?, - }; - for i in &self.function { - write!(f, "{}\n...\n", i.top)?; - } - write!(f, "{}", self.contents)?; - for i in &self.function { - write!(f, "\n...\n{}", i.bottom)?; - } - match &self.block { - None => {} - Some(block) => write!(f, "\n...{}", block.bottom)?, - }; - Ok(()) - } -} - -/// This is used for the functions that are being looked up themeselves but store an outer function that may aontains a function that is being looked up. -#[derive(Debug, Clone)] -pub struct FunctionBlock { - /// The name of the function (parent function) - pub(crate) name: String, - /// what the signature of the function is - pub(crate) top: String, - /// what the last line of the function is - pub(crate) bottom: String, - /// The line number the function starts and ends on - pub(crate) lines: (usize, usize), - /// The lifetime of the function - pub(crate) lifetime: Vec, - /// The generic types of the function - pub(crate) generics: Vec, - /// The arguments of the function - pub(crate) arguments: Vec, - /// The return type of the function - pub(crate) return_type: Option, - /// the function atrributes - pub(crate) attributes: Vec, - /// the functions doc comments - pub(crate) doc_comments: Vec, -} - -impl FunctionBlock { - /// get the metadata for this block ie the name of the block, the type of block, the line number the block starts and ends - pub fn get_metadata(&self) -> HashMap { - let mut map = HashMap::new(); - map.insert("name".to_string(), self.name.clone()); - map.insert("lines".to_string(), format!("{:?}", self.lines)); - map.insert("signature".to_string(), self.top.clone()); - map.insert("bottom".to_string(), self.bottom.clone()); - map.insert("generics".to_string(), self.generics.join(",")); - map.insert("arguments".to_string(), self.arguments.join(",")); - map.insert("lifetime generics".to_string(), self.lifetime.join(",")); - map.insert("attributes".to_string(), self.attributes.join(",")); - map.insert("doc comments".to_string(), self.doc_comments.join(",")); - match &self.return_type { - None => {} - Some(return_type) => { - map.insert("return type".to_string(), return_type.clone()); - } - }; - map - } -} - -/// This holds information about when a function is in an impl/trait/extern block -#[derive(Debug, Clone)] -pub struct Block { - /// The name of the block ie for `impl` it would be the type were impling for - pub(crate) name: Option, - /// The signature of the block - pub(crate) top: String, - /// The last line of the block - pub(crate) bottom: String, - /// the type of block ie `impl` `trait` `extern` - pub(crate) block_type: BlockType, - /// The line number the function starts and ends on - pub(crate) lines: (usize, usize), - /// The lifetime of the function - pub(crate) lifetime: Vec, - /// The generic types of the function - pub(crate) generics: Vec, - /// The blocks atrributes - pub(crate) attributes: Vec, - /// the blocks doc comments - pub(crate) doc_comments: Vec, -} - -impl Block { - /// get the metadata for this block ie the name of the block, the type of block, the line number the block starts and ends - pub fn get_metadata(&self) -> HashMap { - let mut map = HashMap::new(); - if let Some(name) = &self.name { - map.insert("name".to_string(), name.to_string()); - } - map.insert("block".to_string(), format!("{}", self.block_type)); - map.insert("lines".to_string(), format!("{:?}", self.lines)); - map.insert("signature".to_string(), self.top.clone()); - map.insert("bottom".to_string(), self.bottom.clone()); - map.insert("generics".to_string(), self.generics.join(",")); - map.insert("lifetime generics".to_string(), self.lifetime.join(",")); - map.insert("attributes".to_string(), self.attributes.join(",")); - map.insert("doc comments".to_string(), self.doc_comments.join(",")); - map - } -} - -/// This enum is used when filtering commit history only for let say impl and not externs or traits -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum BlockType { - /// This is for `impl` blocks - Impl, - /// This is for `trait` blocks - Extern, - /// This is for `extern` blocks - Trait, - /// This is for code that gets labeled as a block but `get_function_history` can't find a block type - Unknown, -} - -impl BlockType { - /// This is used to get the name of the block type from a string - pub fn from_string(s: &str) -> Self { - match s { - "impl" => Self::Impl, - "extern" => Self::Extern, - "trait" => Self::Trait, - _ => Self::Unknown, - } - } -} - -impl fmt::Display for BlockType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Impl => write!(f, "impl"), - Self::Extern => write!(f, "extern"), - Self::Trait => write!(f, "trait"), - Self::Unknown => write!(f, "unknown"), - } - } -} - /// This is used to store each individual file in a commit and the associated functions in that file. #[derive(Debug, Clone)] -pub struct File { +pub struct File { /// The name of the file pub(crate) name: String, - functions: Vec, - current_pos: usize, + pub(crate)functions: Vec, + pub(crate)current_pos: usize, } -impl File { +impl File { /// Create a new file with the given name and functions - pub fn new(name: String, functions: Vec) -> Self { + pub fn new(name: String, functions: Vec) -> Self { Self { name, functions, @@ -305,69 +24,29 @@ impl File { } } - /// returns a new `File` by filtering the current one by the filter specified (does not modify the current one). - /// - /// valid filters are: `Filter::FunctionInBlock`, `Filter::FunctionInLines`, and `Filter::FunctionWithParent`. - pub fn filter_by(&self, filter: &Filter) -> Result> { - let mut vec = Vec::new(); - for function in &self.functions { - match &filter { - Filter::FunctionInBlock(block_type) => { - if let Some(block) = &function.block { - if block.block_type == *block_type { - vec.push(function.clone()); - } - } - } - Filter::FunctionInLines(start, end) => { - if function.lines.0 >= *start && function.lines.1 <= *end { - vec.push(function.clone()); - } - } - Filter::FunctionWithParent(parent) => { - for parents in &function.function { - if parents.name == *parent { - vec.push(function.clone()); - } - } - } - Filter::None => vec.push(function.clone()), - _ => return Err("Filter not available")?, - } - } - if vec.is_empty() { - return Err("No functions found for filter")?; - } - Ok(Self { - name: self.name.clone(), - functions: vec, - current_pos: 0, - }) - } - /// This is used to get the functions in the file - pub const fn get_functions(&self) -> &Vec { + pub const fn get_functions(&self) -> &Vec { &self.functions } /// This is used to get the functions in the file (mutable) - pub fn get_functions_mut(&mut self) -> &mut Vec { + pub fn get_functions_mut(&mut self) -> &mut Vec { &mut self.functions } /// This is will get the current function in the file - pub fn get_current_function(&self) -> Option<&Function> { + pub fn get_current_function(&self) -> Option<&T> { self.functions.get(self.current_pos) } /// This is will get the current function in the file (mutable) - pub fn get_current_function_mut(&mut self) -> Option<&mut Function> { + pub fn get_current_function_mut(&mut self) -> Option<&mut T> { self.functions.get_mut(self.current_pos) } } -impl Iterator for File { - type Item = Function; +impl Iterator for File { + type Item = T; fn next(&mut self) -> Option { // get the current function without removing it let function = self.functions.get(self.current_pos).cloned(); @@ -376,33 +55,19 @@ impl Iterator for File { } } -impl fmt::Display for File { +impl fmt::Display for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for (i, function) in self.functions.iter().enumerate() { - write!( - f, - "{}", - match i { - 0 => "", - _ => "\n...\n", - }, - )?; - let previous = match i { - 0 => None, - _ => self.functions.get(i - 1), - }; - let next = self.functions.get(i + 1); - function.fmt_with_context(f, previous, next)?; - } - Ok(()) + write!(f, "{}", self.name) } } + + /// This holds information like date and commit `commit_hash` and also the list of function found in the commit. #[derive(Debug, Clone)] -pub struct CommitFunctions { +pub struct CommitFunctions { commit_hash: String, - files: Vec, + files: Vec>, date: DateTime, current_iter_pos: usize, current_pos: usize, @@ -411,11 +76,11 @@ pub struct CommitFunctions { message: String, } -impl CommitFunctions { +impl CommitFunctions { /// Create a new `CommitFunctions` with the given `commit_hash`, functions, and date. pub fn new( commit_hash: String, - files: Vec, + files: Vec>, date: &str, author: String, email: String, @@ -463,12 +128,12 @@ impl CommitFunctions { } /// returns the current file - pub fn get_file(&self) -> &File { + pub fn get_file(&self) -> &File { &self.files[self.current_pos] } /// returns the current file (mutable) - pub fn get_file_mut(&mut self) -> &mut File { + pub fn get_file_mut(&mut self) -> &mut File { &mut self.files[self.current_pos] } @@ -485,7 +150,7 @@ impl CommitFunctions { /// returns a new `CommitFunctions` by filtering the current one by the filter specified (does not modify the current one). /// /// valid filters are: `Filter::FunctionInBlock`, `Filter::FunctionInLines`, `Filter::FunctionWithParent`, and `Filter::FileAbsolute`, `Filter::FileRelative`, and `Filter::Directory`. - pub fn filter_by(&self, filter: &Filter) -> Result> { + pub fn filter_by(&self, filter: &Filter) -> Result> { let mut vec = Vec::new(); for f in &self.files { match filter { @@ -531,8 +196,8 @@ impl CommitFunctions { } } -impl Iterator for CommitFunctions { - type Item = File; +impl Iterator for CommitFunctions { + type Item = File; fn next(&mut self) -> Option { // get the current function without removing it let function = self.files.get(self.current_iter_pos).cloned(); @@ -541,7 +206,7 @@ impl Iterator for CommitFunctions { } } -impl fmt::Display for CommitFunctions { +impl fmt::Display for CommitFunctions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "{}", self.files[self.current_pos])?; Ok(()) @@ -550,16 +215,16 @@ impl fmt::Display for CommitFunctions { /// This struct holds the a list of commits and the function that were looked up for each commit. #[derive(Debug, Clone)] -pub struct FunctionHistory { +pub struct FunctionHistory { pub(crate) name: String, - pub(crate) commit_history: Vec, + pub(crate) commit_history: Vec>, current_iter_pos: usize, current_pos: usize, } -impl FunctionHistory { +impl FunctionHistory { // creates a new `FunctionHistory` from a list of commits - pub fn new(name: String, commit_history: Vec) -> Self { + pub fn new(name: String, commit_history: Vec>) -> Self { Self { name, commit_history, @@ -612,12 +277,12 @@ impl FunctionHistory { } /// returns a mutable reference to the current commit - pub fn get_mut_commit(&mut self) -> &mut CommitFunctions { + pub fn get_mut_commit(&mut self) -> &mut CommitFunctions { &mut self.commit_history[self.current_pos] } /// returns a reference to the current commit - pub fn get_commit(&self) -> &CommitFunctions { + pub fn get_commit(&self) -> &CommitFunctions { &self.commit_history[self.current_pos] } @@ -647,7 +312,7 @@ impl FunctionHistory { /// /// history.filter_by(Filter::Directory("app".to_string())).unwrap(); /// ``` - pub fn filter_by(&self, filter: &Filter) -> Result> { + pub fn filter_by(&self, filter: &Filter) -> Result> { #[cfg(feature = "parallel")] let t = self.commit_history.par_iter(); #[cfg(not(feature = "parallel"))] @@ -693,15 +358,15 @@ impl FunctionHistory { } } -impl fmt::Display for FunctionHistory { +impl fmt::Display for FunctionHistory { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "{}", self.commit_history[self.current_pos])?; Ok(()) } } -impl Iterator for FunctionHistory { - type Item = CommitFunctions; +impl Iterator for FunctionHistory { + type Item = CommitFunctions; fn next(&mut self) -> Option { self.commit_history .get(self.current_iter_pos) From 0b54d49686c88248c194f24cdf662434bec8c7dd Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Fri, 30 Sep 2022 19:50:41 +0000 Subject: [PATCH 003/172] chore: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc3d0000..71d098eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file. - Update changelog - Update changelog - Update changelog +- Update changelog ### Changelog From 721ea9d4e2196f46e199df7ef3ae8b05e0b50bc4 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Fri, 30 Sep 2022 18:15:53 -0400 Subject: [PATCH 004/172] TODO: figure out how to map filers and seraches based languges still wip and doesnt compile --- git-function-history-lib/src/languages/c.rs | 31 ++-- git-function-history-lib/src/languages/mod.rs | 72 +++++++++ .../src/languages/python.rs | 142 +++++++++++++++--- .../src/languages/rust.rs | 1 + git-function-history-lib/src/lib.rs | 2 +- git-function-history-lib/src/types.rs | 10 +- 6 files changed, 214 insertions(+), 44 deletions(-) diff --git a/git-function-history-lib/src/languages/c.rs b/git-function-history-lib/src/languages/c.rs index 15c0c2d5..459137a8 100644 --- a/git-function-history-lib/src/languages/c.rs +++ b/git-function-history-lib/src/languages/c.rs @@ -1,22 +1,23 @@ use std::collections::HashMap; - +#[derive(Debug, Clone)] pub struct Function { - name: String, - body: String, - // parameters: Params, - parameters: Vec, - parent: Vec, - returns: Option, + pub (crate)name: String, + pub (crate)body: String, + pub (crate)parameters: Vec, + pub (crate)parent: Vec, + pub (crate)returns: Option, + pub (crate)lines: (usize, usize), } impl Function { - pub fn new(name: String, body: String, parameters: Vec, parent: Vec, returns: Option) -> Self { + pub fn new(name: String, body: String, parameters: Vec, parent: Vec, returns: Option, lines: (usize, usize)) -> Self { Self { name, body, parameters, parent, returns, + lines, } } } @@ -35,12 +36,12 @@ impl super::Function for Function { todo!() } } - +#[derive(Debug, Clone)] pub struct ParentFunction { - name: String, - top: String, - bottom: String, - lines: (usize, usize), - parameters: Vec, - returns: Option, + pub (crate)name: String, + pub (crate)top: String, + pub (crate) bottom: String, + pub (crate)lines: (usize, usize), + pub (crate)parameters: Vec, + pub (crate)returns: Option, } \ No newline at end of file diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index fbb7caac..fdb12553 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -76,3 +76,75 @@ impl File { } } + +impl File { + pub fn filter_by(&self, filter: &Filter) -> Result> { + let mut vec = Vec::new(); + for function in &self.functions { + match &filter { + Filter::FunctionInBlock(block_type) => { + if let Some(block) = &function.class { + if block.name == *block_type.name { + vec.push(function.clone()); + } + } + } + Filter::FunctionInLines(start, end) => { + if function.lines.0 >= *start && function.lines.1 <= *end { + vec.push(function.clone()); + } + } + Filter::FunctionWithParent(parent) => { + for parents in &function.parent { + if parents.name == *parent { + vec.push(function.clone()); + } + } + } + Filter::None => vec.push(function.clone()), + _ => return Err("Filter not available")?, + } + } + if vec.is_empty() { + return Err("No functions found for filter")?; + } + Ok(Self { + name: self.name.clone(), + functions: vec, + current_pos: 0, + }) + } +} + +impl File { + pub fn filter_by(&self, filter: &Filter) -> Result> { + let mut vec = Vec::new(); + for function in &self.functions { + match &filter { + + Filter::FunctionInLines(start, end) => { + if function.lines.0 >= *start && function.lines.1 <= *end { + vec.push(function.clone()); + } + } + Filter::FunctionWithParent(parent) => { + for parents in &function.parent { + if parents.name == *parent { + vec.push(function.clone()); + } + } + } + Filter::None => vec.push(function.clone()), + _ => return Err("Filter not available")?, + } + } + if vec.is_empty() { + return Err("No functions found for filter")?; + } + Ok(Self { + name: self.name.clone(), + functions: vec, + current_pos: 0, + }) + } +} \ No newline at end of file diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index d8e2ee94..2c687b05 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -4,14 +4,16 @@ use rustpython_parser::{location::Location, ast::{StatementType, Located}, parse use crate::File; +#[derive(Debug, Clone)] pub struct Function { - name: String, - body: String, + pub (crate) name: String, + pub (crate)body: String, // parameters: Params, - parameters: Vec, - parent: Vec, - decorators: Vec, - class: Option, + pub (crate)parameters: Vec, + pub (crate)parent: Vec, + pub (crate)decorators: Vec, + pub (crate)class: Option, + pub (crate)lines: (usize, usize), returns: Option, } @@ -26,38 +28,131 @@ impl super::Function for Function { previous: Option<&Self>, next: Option<&Self>, ) -> std::fmt::Result { - todo!() + match self.class { + Some(class) => { + match previous { + Some(previous) => { + if previous.class.is_some() { + if previous.class.as_ref().unwrap().name == class.name { + write!(f, "\n...\n")?; + } else { + write!(f, "{}", class.top)?; + } + } else { + write!(f, "{}", class.top)?; + } + + } + None => { + writeln!(f, "{}", class.top)?; + } + } + } + None => { + } + + + }; + if !self.parent.is_empty() { + match previous { + None => { + for parent in &self.parent { + writeln!(f, "{}", parent.top)?; + } + } + Some(previous) => { + for parent in &self.parent { + if previous + .parent + .iter() + .any(|x| x.lines == parent.lines) + { + } else { + write!(f, "{}\n...\n", parent.top)?; + } + + } + } + } + } + write!(f, "{}", self.body)?; + if !self.parent.is_empty() { + match next { + None => { + for parent in &self.parent { + writeln!(f, "{}", parent.bottom)?; + } + } + Some(next) => { + for parent in &self.parent { + if next + .parent + .iter() + .any(|x| x.lines == parent.lines) + { + } else { + write!(f, "\n...\n{}", parent.bottom)?; + } + + } + } + } + } + match self.class { + Some(class) => { + match next { + Some(next) => { + if next.class.is_some() { + if next.class.as_ref().unwrap().name == class.name { + write!(f, "\n...\n")?; + } else { + write!(f, "{}", class.bottom)?; + } + } else { + write!(f, "{}", class.bottom)?; + } + + } + None => { + writeln!(f, "{}", class.bottom)?; + } + } + } + None => { + } + }; + Ok(()) } fn get_metadata(&self) -> HashMap<&str, String> { todo!() } } - +#[derive(Debug, Clone)] pub struct Params { args: Vec, kwargs: Vec, varargs: Option, varkwargs: Option, } - +#[derive(Debug, Clone)] pub struct Class { - name: String, - top: String, - bottom: String, - lines: (usize, usize), - decorators: Vec, + pub (crate)name: String, + pub (crate)top: String, + pub (crate)bottom: String, + pub (crate)lines: (usize, usize), + pub (crate)decorators: Vec, } - +#[derive(Debug, Clone)] pub struct ParentFunction { - name: String, - top: String, - bottom: String, - lines: (usize, usize), - parameters: Vec, - decorators: Vec, - class: Option, - returns: Option, + pub (crate)name: String, + pub (crate)top: String, + pub (crate)bottom: String, + pub (crate)lines: (usize, usize), + pub (crate)parameters: Vec, + pub (crate)decorators: Vec, + pub (crate)class: Option, + pub (crate)returns: Option, } pub fn get_file_in_commit( @@ -110,6 +205,7 @@ pub fn get_file_in_commit( .collect(), class: None, body, + lines: (* start , *end), }; new.push(new_func); } diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 852ba60d..c67967f2 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -46,6 +46,7 @@ impl super::Function for Function { None => write!(f, "{}\n...\n", block.top)?, Some(previous_function) => match &previous_function.block { None => write!(f, "{}\n...\n", block.top)?, + // TODO: chek for different blocks Some(previous_block) => { if previous_block.lines == block.lines { } else { diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index f11bbd2f..2fd1fb3c 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -102,7 +102,7 @@ pub enum Filter { /// ``` #[allow(clippy::too_many_lines)] // TODO: split this function into smaller functions -pub fn get_function_history( +pub fn get_function_history( name: &str, file: &FileType, filter: Filter, diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index dff4602d..68cbbfc1 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -65,7 +65,7 @@ impl fmt::Display for File { /// This holds information like date and commit `commit_hash` and also the list of function found in the commit. #[derive(Debug, Clone)] -pub struct CommitFunctions { +pub struct CommitFunctions { commit_hash: String, files: Vec>, date: DateTime, @@ -206,7 +206,7 @@ impl Iterator for CommitFunctions { } } -impl fmt::Display for CommitFunctions { +impl fmt::Display for CommitFunctions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "{}", self.files[self.current_pos])?; Ok(()) @@ -215,14 +215,14 @@ impl fmt::Display for CommitFunctions { /// This struct holds the a list of commits and the function that were looked up for each commit. #[derive(Debug, Clone)] -pub struct FunctionHistory { +pub struct FunctionHistory { pub(crate) name: String, pub(crate) commit_history: Vec>, current_iter_pos: usize, current_pos: usize, } -impl FunctionHistory { +impl FunctionHistory { // creates a new `FunctionHistory` from a list of commits pub fn new(name: String, commit_history: Vec>) -> Self { Self { @@ -358,7 +358,7 @@ impl FunctionHistory { } } -impl fmt::Display for FunctionHistory { +impl fmt::Display for FunctionHistory { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "{}", self.commit_history[self.current_pos])?; Ok(()) From 21509e87ed4bc4b73fbeafef0e535a2eee3d7c34 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Fri, 30 Sep 2022 22:16:32 +0000 Subject: [PATCH 005/172] chore: update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71d098eb..92b66cff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,11 @@ All notable changes to this project will be documented in this file. - Update changelog - Update changelog - Update changelog +- Update changelog + +### TODO + +- Figure out how to map filers and seraches based languges ### Changelog From 5b370221eac5e35632bdc09fcdd9bcf25eaae3a5 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 2 Oct 2022 13:49:45 -0400 Subject: [PATCH 006/172] so chnagelog commit dont get pushed into the changlog --- .github/workflows/chanelog.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/chanelog.yaml b/.github/workflows/chanelog.yaml index bb179675..d1c96f64 100644 --- a/.github/workflows/chanelog.yaml +++ b/.github/workflows/chanelog.yaml @@ -25,6 +25,6 @@ jobs: - name: Commit the changelog uses: EndBug/add-and-commit@v7 with: - message: "chore: update changelog" + message: "update changelog" add: ${{ steps.git-cliff.outputs.changelog }} \ No newline at end of file From efb030cac7db98fb2b4d0916af276ee5267b7c80 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Sun, 2 Oct 2022 17:50:26 +0000 Subject: [PATCH 007/172] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92b66cff..12f67c01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file. - Update changelog - Update changelog - Update changelog +- Update changelog ### TODO From 3e726b3b75ad4c30b1b65ec9f2f46214d2633666 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 2 Oct 2022 16:49:01 -0400 Subject: [PATCH 008/172] lib: moved away from using mostly enerics to using enums b/c i dont understand how to use generics code is very messy and needs to be clenaed up, rethout and documented still doenst compile but much closer --- git-function-history-lib/src/languages/c.rs | 47 +++- git-function-history-lib/src/languages/mod.rs | 239 ++++++++-------- .../src/languages/python.rs | 154 +++++------ .../src/languages/rust.rs | 29 +- git-function-history-lib/src/lib.rs | 170 ++++++------ git-function-history-lib/src/types.rs | 259 +++++++++--------- 6 files changed, 459 insertions(+), 439 deletions(-) diff --git a/git-function-history-lib/src/languages/c.rs b/git-function-history-lib/src/languages/c.rs index 459137a8..0ba3030f 100644 --- a/git-function-history-lib/src/languages/c.rs +++ b/git-function-history-lib/src/languages/c.rs @@ -1,16 +1,25 @@ -use std::collections::HashMap; +use std::{collections::HashMap, error::Error}; + +use super::FunctionResult; #[derive(Debug, Clone)] pub struct Function { - pub (crate)name: String, - pub (crate)body: String, - pub (crate)parameters: Vec, - pub (crate)parent: Vec, - pub (crate)returns: Option, - pub (crate)lines: (usize, usize), + pub(crate) name: String, + pub(crate) body: String, + pub(crate) parameters: Vec, + pub(crate) parent: Vec, + pub(crate) returns: Option, + pub(crate) lines: (usize, usize), } impl Function { - pub fn new(name: String, body: String, parameters: Vec, parent: Vec, returns: Option, lines: (usize, usize)) -> Self { + pub fn new( + name: String, + body: String, + parameters: Vec, + parent: Vec, + returns: Option, + lines: (usize, usize), + ) -> Self { Self { name, body, @@ -38,10 +47,18 @@ impl super::Function for Function { } #[derive(Debug, Clone)] pub struct ParentFunction { - pub (crate)name: String, - pub (crate)top: String, - pub (crate) bottom: String, - pub (crate)lines: (usize, usize), - pub (crate)parameters: Vec, - pub (crate)returns: Option, -} \ No newline at end of file + pub(crate) name: String, + pub(crate) top: String, + pub(crate) bottom: String, + pub(crate) lines: (usize, usize), + pub(crate) parameters: Vec, + pub(crate) returns: Option, +} + +pub(crate) fn find_function_in_commit( + commit: &str, + file_path: &str, + name: &str, +) -> FunctionResult { + todo!("find_function_in_commit") +} diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index fdb12553..b5b0a6f7 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -1,4 +1,4 @@ -use std::{fmt, collections::HashMap, error::Error}; +use std::{collections::HashMap, error::Error, fmt}; use crate::{File, Filter}; @@ -11,21 +11,19 @@ pub enum Language { C, } -pub mod c; -pub mod python; -pub mod rust; - - -// make macro that turns a language into its function struct -macro_rules! language { - ($name:ident, $struct:ident) => { - pub fn $name() -> Language { - Language::$struct +impl fmt::Display for Language { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Language::Python => write!(f, "python"), + Language::Rust => write!(f, "rust"), + Language::C => write!(f, "c"), } - }; + } } -language!(python, Python); +pub mod c; +pub mod python; +pub mod rust; pub trait Function { fn fmt_with_context( @@ -37,114 +35,115 @@ pub trait Function { fn get_metadata(&self) -> HashMap<&str, String>; } -impl File { - pub fn filter_by(&self, filter: &Filter) -> Result> { - let mut vec = Vec::new(); - for function in &self.functions { - match &filter { - Filter::FunctionInBlock(block_type) => { - if let Some(block) = &function.block { - if block.block_type == *block_type { - vec.push(function.clone()); - } - } - } - Filter::FunctionInLines(start, end) => { - if function.lines.0 >= *start && function.lines.1 <= *end { - vec.push(function.clone()); - } - } - Filter::FunctionWithParent(parent) => { - for parents in &function.function { - if parents.name == *parent { - vec.push(function.clone()); - } - } - } - Filter::None => vec.push(function.clone()), - _ => return Err("Filter not available")?, - } - } - if vec.is_empty() { - return Err("No functions found for filter")?; - } - Ok(Self { - name: self.name.clone(), - functions: vec, - current_pos: 0, - }) - } -} +pub type FunctionResult = Result, Box>; +// impl File { +// pub fn filter_by(&self, filter: &Filter) -> Result> { +// let mut vec = Vec::new(); +// for function in &self.functions { +// match &filter { +// Filter::FunctionInBlock(block_type) => { +// if let Some(block) = &function.block { +// if block.block_type == *block_type { +// vec.push(function.clone()); +// } +// } +// } +// Filter::FunctionInLines(start, end) => { +// if function.lines.0 >= *start && function.lines.1 <= *end { +// vec.push(function.clone()); +// } +// } +// Filter::FunctionWithParent(parent) => { +// for parents in &function.function { +// if parents.name == *parent { +// vec.push(function.clone()); +// } +// } +// } +// Filter::None => vec.push(function.clone()), +// _ => return Err("Filter not available")?, +// } +// } +// if vec.is_empty() { +// return Err("No functions found for filter")?; +// } +// Ok(Self { +// name: self.name.clone(), +// functions: vec, +// current_pos: 0, +// }) +// } +// } -impl File { - pub fn filter_by(&self, filter: &Filter) -> Result> { - let mut vec = Vec::new(); - for function in &self.functions { - match &filter { - Filter::FunctionInBlock(block_type) => { - if let Some(block) = &function.class { - if block.name == *block_type.name { - vec.push(function.clone()); - } - } - } - Filter::FunctionInLines(start, end) => { - if function.lines.0 >= *start && function.lines.1 <= *end { - vec.push(function.clone()); - } - } - Filter::FunctionWithParent(parent) => { - for parents in &function.parent { - if parents.name == *parent { - vec.push(function.clone()); - } - } - } - Filter::None => vec.push(function.clone()), - _ => return Err("Filter not available")?, - } - } - if vec.is_empty() { - return Err("No functions found for filter")?; - } - Ok(Self { - name: self.name.clone(), - functions: vec, - current_pos: 0, - }) - } -} +// impl File { +// pub fn filter_by(&self, filter: &Filter) -> Result> { +// let mut vec = Vec::new(); +// for function in &self.functions { +// match &filter { +// Filter::FunctionInBlock(block_type) => { +// if let Some(block) = &function.class { +// if block.name == *block_type.name { +// vec.push(function.clone()); +// } +// } +// } +// Filter::FunctionInLines(start, end) => { +// if function.lines.0 >= *start && function.lines.1 <= *end { +// vec.push(function.clone()); +// } +// } +// Filter::FunctionWithParent(parent) => { +// for parents in &function.parent { +// if parents.name == *parent { +// vec.push(function.clone()); +// } +// } +// } +// Filter::None => vec.push(function.clone()), +// _ => return Err("Filter not available")?, +// } +// } +// if vec.is_empty() { +// return Err("No functions found for filter")?; +// } +// Ok(Self { +// name: self.name.clone(), +// functions: vec, +// current_pos: 0, +// }) +// } +// } -impl File { - pub fn filter_by(&self, filter: &Filter) -> Result> { - let mut vec = Vec::new(); - for function in &self.functions { - match &filter { +// impl File { +// pub fn filter_by(&self, filter: &Filter) -> Result> { +// let mut vec = Vec::new(); +// for function in &self.functions { +// match &filter { - Filter::FunctionInLines(start, end) => { - if function.lines.0 >= *start && function.lines.1 <= *end { - vec.push(function.clone()); - } - } - Filter::FunctionWithParent(parent) => { - for parents in &function.parent { - if parents.name == *parent { - vec.push(function.clone()); - } - } - } - Filter::None => vec.push(function.clone()), - _ => return Err("Filter not available")?, - } - } - if vec.is_empty() { - return Err("No functions found for filter")?; - } - Ok(Self { - name: self.name.clone(), - functions: vec, - current_pos: 0, - }) - } -} \ No newline at end of file +// Filter::FunctionInLines(start, end) => { +// if function.lines.0 >= *start && function.lines.1 <= *end { +// vec.push(function.clone()); +// } +// } +// Filter::FunctionWithParent(parent) => { +// for parents in &function.parent { +// if parents.name == *parent { +// vec.push(function.clone()); +// } +// } +// } +// Filter::None => vec.push(function.clone()), +// _ => return Err("Filter not available")?, +// } +// } +// if vec.is_empty() { +// return Err("No functions found for filter")?; +// } +// Ok(Self { +// name: self.name.clone(), +// functions: vec, +// current_pos: 0, +// }) +// } +// } diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 2c687b05..6899b984 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -1,25 +1,29 @@ -use std::{error::Error, collections::HashMap}; +use std::collections::HashMap; -use rustpython_parser::{location::Location, ast::{StatementType, Located}, parser}; +use rustpython_parser::{ + ast::{Located, StatementType}, + location::Location, + parser, +}; use crate::File; +use super::FunctionResult; + #[derive(Debug, Clone)] pub struct Function { - pub (crate) name: String, - pub (crate)body: String, + pub(crate) name: String, + pub(crate) body: String, // parameters: Params, - pub (crate)parameters: Vec, - pub (crate)parent: Vec, - pub (crate)decorators: Vec, - pub (crate)class: Option, - pub (crate)lines: (usize, usize), + pub(crate) parameters: Vec, + pub(crate) parent: Vec, + pub(crate) decorators: Vec, + pub(crate) class: Option, + pub(crate) lines: (usize, usize), returns: Option, } -impl Function { - -} +impl Function {} impl super::Function for Function { fn fmt_with_context( @@ -28,30 +32,24 @@ impl super::Function for Function { previous: Option<&Self>, next: Option<&Self>, ) -> std::fmt::Result { - match self.class { - Some(class) => { - match previous { - Some(previous) => { - if previous.class.is_some() { - if previous.class.as_ref().unwrap().name == class.name { - write!(f, "\n...\n")?; - } else { - write!(f, "{}", class.top)?; - } + match &self.class { + Some(class) => match previous { + Some(previous) => { + if previous.class.is_some() { + if previous.class.as_ref().unwrap().name == class.name { + write!(f, "\n...\n")?; } else { write!(f, "{}", class.top)?; } - - } - None => { - writeln!(f, "{}", class.top)?; + } else { + write!(f, "{}", class.top)?; } } - } - None => { - } - - + None => { + writeln!(f, "{}", class.top)?; + } + }, + None => {} }; if !self.parent.is_empty() { match previous { @@ -59,18 +57,13 @@ impl super::Function for Function { for parent in &self.parent { writeln!(f, "{}", parent.top)?; } - } + } Some(previous) => { for parent in &self.parent { - if previous - .parent - .iter() - .any(|x| x.lines == parent.lines) - { - } else { - write!(f, "{}\n...\n", parent.top)?; - } - + if previous.parent.iter().any(|x| x.lines == parent.lines) { + } else { + write!(f, "{}\n...\n", parent.top)?; + } } } } @@ -82,44 +75,35 @@ impl super::Function for Function { for parent in &self.parent { writeln!(f, "{}", parent.bottom)?; } - } + } Some(next) => { for parent in &self.parent { - if next - .parent - .iter() - .any(|x| x.lines == parent.lines) - { - } else { - write!(f, "\n...\n{}", parent.bottom)?; - } - + if next.parent.iter().any(|x| x.lines == parent.lines) { + } else { + write!(f, "\n...\n{}", parent.bottom)?; + } } } } } - match self.class { - Some(class) => { - match next { - Some(next) => { - if next.class.is_some() { - if next.class.as_ref().unwrap().name == class.name { - write!(f, "\n...\n")?; - } else { - write!(f, "{}", class.bottom)?; - } + match &self.class { + Some(class) => match next { + Some(next) => { + if next.class.is_some() { + if next.class.as_ref().unwrap().name == class.name { + write!(f, "\n...\n")?; } else { write!(f, "{}", class.bottom)?; } - - } - None => { - writeln!(f, "{}", class.bottom)?; + } else { + write!(f, "{}", class.bottom)?; } } - } - None => { - } + None => { + writeln!(f, "{}", class.bottom)?; + } + }, + None => {} }; Ok(()) } @@ -137,29 +121,29 @@ pub struct Params { } #[derive(Debug, Clone)] pub struct Class { - pub (crate)name: String, - pub (crate)top: String, - pub (crate)bottom: String, - pub (crate)lines: (usize, usize), - pub (crate)decorators: Vec, + pub(crate) name: String, + pub(crate) top: String, + pub(crate) bottom: String, + pub(crate) lines: (usize, usize), + pub(crate) decorators: Vec, } #[derive(Debug, Clone)] pub struct ParentFunction { - pub (crate)name: String, - pub (crate)top: String, - pub (crate)bottom: String, - pub (crate)lines: (usize, usize), - pub (crate)parameters: Vec, - pub (crate)decorators: Vec, - pub (crate)class: Option, - pub (crate)returns: Option, + pub(crate) name: String, + pub(crate) top: String, + pub(crate) bottom: String, + pub(crate) lines: (usize, usize), + pub(crate) parameters: Vec, + pub(crate) decorators: Vec, + pub(crate) class: Option, + pub(crate) returns: Option, } -pub fn get_file_in_commit( +pub(crate) fn find_function_in_commit( commit: &str, file_path: &str, name: &str, -) -> Result, Box> { +) -> Result, Box> { let file_contents = crate::find_file_in_commit(commit, file_path)?; let ast = parser::parse_program(&file_contents)?; let mut functions = vec![]; @@ -205,12 +189,12 @@ pub fn get_file_in_commit( .collect(), class: None, body, - lines: (* start , *end), + lines: (*start, *end), }; new.push(new_func); } } - Ok(File::new(name.to_string(), new)) + Ok(new) } fn fun_name1( diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index c67967f2..58f81313 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -1,10 +1,12 @@ -use std::{collections::HashMap, fmt, error::Error}; +use std::{collections::HashMap, error::Error, fmt}; use ra_ap_syntax::{ ast::{self, HasDocComments, HasGenericParams, HasName}, AstNode, SourceFile, SyntaxKind, }; +use super::FunctionResult; + /// This holds the information about a single function each commit will have multiple of these. #[derive(Debug, Clone)] pub struct Function { @@ -46,7 +48,7 @@ impl super::Function for Function { None => write!(f, "{}\n...\n", block.top)?, Some(previous_function) => match &previous_function.block { None => write!(f, "{}\n...\n", block.top)?, - // TODO: chek for different blocks + // TODO: chek for different blocks Some(previous_block) => { if previous_block.lines == block.lines { } else { @@ -128,21 +130,18 @@ impl super::Function for Function { }; map } - - } impl Function { - /// get the parent functions - pub fn get_parent_function(&self) -> Vec { - self.function.clone() - } - - /// get the block of the function - pub fn get_block(&self) -> Option { - self.block.clone() - } - + /// get the parent functions + pub fn get_parent_function(&self) -> Vec { + self.function.clone() + } + + /// get the block of the function + pub fn get_block(&self) -> Option { + self.block.clone() + } } impl fmt::Display for Function { @@ -294,7 +293,7 @@ impl fmt::Display for BlockType { #[allow(clippy::too_many_lines)] // TODO: split this function into smaller functions -fn find_function_in_commit( +pub(crate) fn find_function_in_commit( commit: &str, file_path: &str, name: &str, diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 2fd1fb3c..575c23f8 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -18,13 +18,14 @@ pub mod languages; /// Different types that can extracted from the result of `get_function_history`. pub mod types; +use languages::{python, rust, Function}; #[cfg(feature = "parallel")] use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use std::{error::Error, process::Command}; -pub use types::{ - CommitFunctions, File, FunctionHistory -}; +pub use types::{CommitFunctions, File, FunctionHistory}; + +use crate::languages::Language; /// Different filetypes that can be used to ease the process of finding functions using `get_function_history`. #[derive(Debug, Clone, PartialEq, Eq)] @@ -42,7 +43,7 @@ pub enum FileType { // TODO: Add support for filtering by generic parameters, lifetimes, and return types. /// This is filter enum is used when you want to lookup a function with the filter of filter a previous lookup. #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Filter { +pub enum Filter { /// When you want to filter by a commit hash. CommitHash(String), /// When you want to filter by a specific date (in rfc2822 format). @@ -55,11 +56,11 @@ pub enum Filter { FileRelative(String), /// When you want to filter only files in a specific directory Directory(String), - // when you want to filter by function that are in a specific block (impl, trait, extern) - FunctionInBlock(Block), - // when you want to filter by function that are in between specific lines + /// when you want to filter by function that are in a specific block (impl, trait, extern) + // FunctionInBlock(Block), + /// when you want to filter by function that are in between specific lines FunctionInLines(usize, usize), - // when you want filter by a function that has a parent function of a specific name + /// when you want filter by a function that has a parent function of a specific name FunctionWithParent(String), /// when you want to filter by a any commit author name that contains a specific string Author(String), @@ -102,12 +103,11 @@ pub enum Filter { /// ``` #[allow(clippy::too_many_lines)] // TODO: split this function into smaller functions -pub fn get_function_history( +pub fn get_function_history( name: &str, file: &FileType, - filter: Filter, - languages: &[languages::Language], -) -> Result, Box> { + langs: &languages::Language, +) -> Result> { // chack if name is empty if name.is_empty() { Err("function name is empty")?; @@ -119,40 +119,40 @@ pub fn get_function_history( command.arg("log"); command.arg("--pretty=%H;%aD;%aN;%aE;%s"); command.arg("--date=rfc2822"); - match filter { - Filter::CommitHash(hash) => { - command.arg(hash); - command.arg("-n"); - command.arg("1"); - } - Filter::Date(date) => { - command.arg("--since"); - command.arg(date); - command.arg("--max-count=1"); - } - Filter::DateRange(start, end) => { - command.arg("--since"); - command.arg(start); - command.arg("--until"); - command.arg(end); - } - Filter::Author(author) => { - command.arg("--author"); - command.arg(author); - } - Filter::AuthorEmail(email) => { - command.arg("--author"); - command.arg(email); - } - Filter::Message(message) => { - command.arg("--grep"); - command.arg(message); - } - Filter::None => {} - _ => { - Err("filter not supported")?; - } - } + // match filter { + // Filter::CommitHash(hash) => { + // command.arg(hash); + // command.arg("-n"); + // command.arg("1"); + // } + // Filter::Date(date) => { + // command.arg("--since"); + // command.arg(date); + // command.arg("--max-count=1"); + // } + // Filter::DateRange(start, end) => { + // command.arg("--since"); + // command.arg(start); + // command.arg("--until"); + // command.arg(end); + // } + // Filter::Author(author) => { + // command.arg("--author"); + // command.arg(author); + // } + // Filter::AuthorEmail(email) => { + // command.arg("--author"); + // command.arg(email); + // } + // Filter::Message(message) => { + // command.arg("--grep"); + // command.arg(message); + // } + // Filter::None => {} + // _ => { + // Err("filter not supported")?; + // } + // } let output = command.output()?; if !output.stderr.is_empty() { return Err(String::from_utf8(output.stderr)?)?; @@ -195,20 +195,22 @@ pub fn get_function_history( let t = commits.iter(); file_history.commit_history = t .filter_map(|commit| match &file { - FileType::Absolute(path) => match find_function_in_commit(commit.0, path, name) { - Ok(contents) => Some(CommitFunctions::new( - commit.0.to_string(), - vec![File::new(path.to_string(), contents)], - commit.1, - commit.2.to_string(), - commit.3.to_string(), - commit.4.to_string(), - )), - Err(_) => None, - }, + FileType::Absolute(path) => { + match find_function_in_commit(commit.0, path, name, langs) { + Ok(contents) => Some(CommitFunctions::new( + commit.0.to_string(), + vec![File::new(path.to_string(), contents)], + commit.1, + commit.2.to_string(), + commit.3.to_string(), + commit.4.to_string(), + )), + Err(_) => None, + } + } FileType::Relative(_) => { - match find_function_in_commit_with_filetype(commit.0, name, file) { + match find_function_in_commit_with_filetype(commit.0, name, file, langs) { Ok(contents) => Some(CommitFunctions::new( commit.0.to_string(), contents, @@ -222,7 +224,7 @@ pub fn get_function_history( } FileType::None | FileType::Directory(_) => { - match find_function_in_commit_with_filetype(commit.0, name, file) { + match find_function_in_commit_with_filetype(commit.0, name, file, langs) { Ok(contents) => Some(CommitFunctions::new( commit.0.to_string(), contents, @@ -276,12 +278,12 @@ fn find_file_in_commit(commit: &str, file_path: &str) -> Result( +fn find_function_in_commit_with_filetype( commit: &str, name: &str, filetype: &FileType, -) -> Result>, Box> { + langs: &Language, +) -> Result, Box> { // get a list of all the files in the repository let mut files = Vec::new(); let command = Command::new("git") @@ -317,10 +319,12 @@ fn find_function_in_commit_with_filetype( #[cfg(not(feature = "parellel"))] let t = files.iter(); let returns: Vec = t - .filter_map(|file| match find_function_in_commit(commit, file, name) { - Ok(functions) => Some(File::new((*file).to_string(), functions)), - Err(_) => None, - }) + .filter_map( + |file| match find_function_in_commit(commit, file, name, langs) { + Ok(functions) => Some(File::new((*file).to_string(), functions)), + Err(_) => None, + }, + ) .collect(); if returns.is_empty() { Err(err)?; @@ -352,8 +356,8 @@ mod tests { let output = get_function_history( "empty_test", &FileType::Relative("src/test_functions.rs".to_string()), - Filter::None, - languages::Language::Rust, + // Filter::None, + &languages::Language::Rust, ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); @@ -370,8 +374,8 @@ mod tests { let output = get_function_history( "empty_test", &FileType::Absolute("src/test_functions.rs".to_string()), - Filter::None, - languages::Language::Rust, + // Filter::None, + &languages::Language::Rust, ); // assert that err is "not git is not installed" if output.is_err() { @@ -384,8 +388,8 @@ mod tests { let output = get_function_history( "Not_a_function", &FileType::Absolute("src/test_functions.rs".to_string()), - Filter::None, - languages::Language::Rust, + // Filter::None, + &languages::Language::Rust, ); match &output { Ok(output) => println!("{}", output), @@ -399,8 +403,8 @@ mod tests { let output = get_function_history( "empty_test", &FileType::Absolute("src/test_functions.txt".to_string()), - Filter::None, - languages::Language::Rust, + // Filter::None, + &languages::Language::Rust, ); assert!(output.is_err()); assert_eq!(output.unwrap_err().to_string(), "file is not a rust file"); @@ -411,11 +415,11 @@ mod tests { let output = get_function_history( "empty_test", &FileType::None, - Filter::DateRange( - "17 Aug 2022 11:27:23 -0400".to_owned(), - "19 Aug 2022 23:45:52 +0000".to_owned(), - ), - languages::Language::Rust, + // Filter::DateRange( + // "17 Aug 2022 11:27:23 -0400".to_owned(), + // "19 Aug 2022 23:45:52 +0000".to_owned(), + // ), + &languages::Language::Rust, ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); @@ -431,8 +435,12 @@ mod tests { #[test] fn expensive_tes() { let now = Utc::now(); - let output = get_function_history("empty_test", &FileType::None, Filter::None - , languages::Language::Rust); + let output = get_function_history( + "empty_test", + &FileType::None, + // Filter::None, + &languages::Language::Rust, + ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); match &output { diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 68cbbfc1..b209da7a 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -3,20 +3,23 @@ use chrono::{DateTime, FixedOffset}; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use std::{collections::HashMap, error::Error, fmt}; -use crate::Filter; +use crate::{ + languages::{c, python, rust, Function, Language}, + Filter, +}; /// This is used to store each individual file in a commit and the associated functions in that file. #[derive(Debug, Clone)] -pub struct File { +pub struct File { /// The name of the file pub(crate) name: String, - pub(crate)functions: Vec, - pub(crate)current_pos: usize, + pub(crate) functions: Vec, + pub(crate) current_pos: usize, } -impl File { +impl File { /// Create a new file with the given name and functions - pub fn new(name: String, functions: Vec) -> Self { + pub fn new(name: String, functions: Vec) -> Self { Self { name, functions, @@ -25,28 +28,28 @@ impl File { } /// This is used to get the functions in the file - pub const fn get_functions(&self) -> &Vec { + pub const fn get_functions(&self) -> &Vec { &self.functions } /// This is used to get the functions in the file (mutable) - pub fn get_functions_mut(&mut self) -> &mut Vec { + pub fn get_functions_mut(&mut self) -> &mut Vec { &mut self.functions } /// This is will get the current function in the file - pub fn get_current_function(&self) -> Option<&T> { + pub fn get_current_function(&self) -> Option<&FileType> { self.functions.get(self.current_pos) } /// This is will get the current function in the file (mutable) - pub fn get_current_function_mut(&mut self) -> Option<&mut T> { + pub fn get_current_function_mut(&mut self) -> Option<&mut FileType> { self.functions.get_mut(self.current_pos) } } -impl Iterator for File { - type Item = T; +impl Iterator for File { + type Item = FileType; fn next(&mut self) -> Option { // get the current function without removing it let function = self.functions.get(self.current_pos).cloned(); @@ -55,19 +58,26 @@ impl Iterator for File { } } -impl fmt::Display for File { +impl fmt::Display for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.name) } } - - +#[derive(Debug, Clone)] +pub enum FileType { + /// The python language + Python(python::Function), + /// The rust language + Rust(rust::Function), + /// c language + C(c::Function), +} /// This holds information like date and commit `commit_hash` and also the list of function found in the commit. #[derive(Debug, Clone)] -pub struct CommitFunctions { +pub struct CommitFunctions { commit_hash: String, - files: Vec>, + files: Vec, date: DateTime, current_iter_pos: usize, current_pos: usize, @@ -76,11 +86,11 @@ pub struct CommitFunctions { message: String, } -impl CommitFunctions { +impl CommitFunctions { /// Create a new `CommitFunctions` with the given `commit_hash`, functions, and date. pub fn new( commit_hash: String, - files: Vec>, + files: Vec, date: &str, author: String, email: String, @@ -128,12 +138,12 @@ impl CommitFunctions { } /// returns the current file - pub fn get_file(&self) -> &File { + pub fn get_file(&self) -> &File { &self.files[self.current_pos] } /// returns the current file (mutable) - pub fn get_file_mut(&mut self) -> &mut File { + pub fn get_file_mut(&mut self) -> &mut File { &mut self.files[self.current_pos] } @@ -150,54 +160,55 @@ impl CommitFunctions { /// returns a new `CommitFunctions` by filtering the current one by the filter specified (does not modify the current one). /// /// valid filters are: `Filter::FunctionInBlock`, `Filter::FunctionInLines`, `Filter::FunctionWithParent`, and `Filter::FileAbsolute`, `Filter::FileRelative`, and `Filter::Directory`. - pub fn filter_by(&self, filter: &Filter) -> Result> { - let mut vec = Vec::new(); - for f in &self.files { - match filter { - Filter::FileAbsolute(file) => { - if f.name == *file { - vec.push(f.clone()); - } - } - Filter::FileRelative(file) => { - if f.name.ends_with(file) { - vec.push(f.clone()); - } - } - Filter::Directory(dir) => { - if f.name.contains(dir) { - vec.push(f.clone()); - } - } - Filter::FunctionInLines(..) - | Filter::FunctionWithParent(_) - | Filter::FunctionInBlock(_) => { - if f.filter_by(filter).is_ok() { - vec.push(f.clone()); - } - } - Filter::None => vec.push(f.clone()), - _ => Err("Invalid filter")?, - } - } - if vec.is_empty() { - return Err("No files found for filter")?; - } - Ok(Self { - commit_hash: self.commit_hash.clone(), - files: vec, - date: self.date, - current_pos: 0, - current_iter_pos: 0, - author: self.author.clone(), - email: self.email.clone(), - message: self.message.clone(), - }) + pub fn filter_by(&self, filter: &Filter) -> Result> { + // let mut vec = Vec::new(); + // for f in &self.files { + // match filter { + // Filter::FileAbsolute(file) => { + // if f.name == *file { + // vec.push(f.clone()); + // } + // } + // Filter::FileRelative(file) => { + // if f.name.ends_with(file) { + // vec.push(f.clone()); + // } + // } + // Filter::Directory(dir) => { + // if f.name.contains(dir) { + // vec.push(f.clone()); + // } + // } + // Filter::FunctionInLines(..) + // | Filter::FunctionWithParent(_) + // | Filter::FunctionInBlock(_) => { + // if f.filter_by(filter).is_ok() { + // vec.push(f.clone()); + // } + // } + // Filter::None => vec.push(f.clone()), + // _ => Err("Invalid filter")?, + // } + // } + // if vec.is_empty() { + // return Err("No files found for filter")?; + // } + // Ok(Self { + // commit_hash: self.commit_hash.clone(), + // files: vec, + // date: self.date, + // current_pos: 0, + // current_iter_pos: 0, + // author: self.author.clone(), + // email: self.email.clone(), + // message: self.message.clone(), + // }) + todo!() } } -impl Iterator for CommitFunctions { - type Item = File; +impl Iterator for CommitFunctions { + type Item = File; fn next(&mut self) -> Option { // get the current function without removing it let function = self.files.get(self.current_iter_pos).cloned(); @@ -206,7 +217,7 @@ impl Iterator for CommitFunctions { } } -impl fmt::Display for CommitFunctions { +impl fmt::Display for CommitFunctions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "{}", self.files[self.current_pos])?; Ok(()) @@ -215,16 +226,17 @@ impl fmt::Display for CommitFunctions { /// This struct holds the a list of commits and the function that were looked up for each commit. #[derive(Debug, Clone)] -pub struct FunctionHistory { +pub struct FunctionHistory { pub(crate) name: String, - pub(crate) commit_history: Vec>, + pub(crate) commit_history: Vec, + current_iter_pos: usize, current_pos: usize, } -impl FunctionHistory { +impl FunctionHistory { // creates a new `FunctionHistory` from a list of commits - pub fn new(name: String, commit_history: Vec>) -> Self { + pub fn new(name: String, commit_history: Vec) -> Self { Self { name, commit_history, @@ -277,12 +289,12 @@ impl FunctionHistory { } /// returns a mutable reference to the current commit - pub fn get_mut_commit(&mut self) -> &mut CommitFunctions { + pub fn get_mut_commit(&mut self) -> &mut CommitFunctions { &mut self.commit_history[self.current_pos] } /// returns a reference to the current commit - pub fn get_commit(&self) -> &CommitFunctions { + pub fn get_commit(&self) -> &CommitFunctions { &self.commit_history[self.current_pos] } @@ -312,61 +324,62 @@ impl FunctionHistory { /// /// history.filter_by(Filter::Directory("app".to_string())).unwrap(); /// ``` - pub fn filter_by(&self, filter: &Filter) -> Result> { - #[cfg(feature = "parallel")] - let t = self.commit_history.par_iter(); - #[cfg(not(feature = "parallel"))] - let t = self.commit_history.iter(); - let vec: Vec = t - .filter(|f| match filter { - Filter::FunctionInLines(..) - | Filter::FunctionWithParent(_) - | Filter::FunctionInBlock(_) - | Filter::Directory(_) - | Filter::FileAbsolute(_) - | Filter::FileRelative(_) => f.filter_by(filter).is_ok(), - Filter::CommitHash(commit_hash) => &f.commit_hash == commit_hash, - Filter::Date(date) => &f.date.to_rfc2822() == date, - Filter::DateRange(start, end) => { - let start = match DateTime::parse_from_rfc2822(start) { - Ok(date) => date, - Err(_) => return false, - }; - let end = match DateTime::parse_from_rfc2822(end) { - Ok(date) => date, - Err(_) => return false, - }; - f.date >= start || f.date <= end - } - Filter::Author(author) => &f.author == author, - Filter::AuthorEmail(email) => &f.email == email, - Filter::Message(message) => f.message.contains(message), - Filter::None => true, - }) - .cloned() - .collect(); - - if vec.is_empty() { - return Err("No history found for the filter")?; - } - Ok(Self { - commit_history: vec, - name: self.name.clone(), - current_pos: 0, - current_iter_pos: 0, - }) + pub fn filter_by(&self, filter: &Filter) -> Result> { + // #[cfg(feature = "parallel")] + // let t = self.commit_history.par_iter(); + // #[cfg(not(feature = "parallel"))] + // let t = self.commit_history.iter(); + // let vec: Vec = t + // .filter(|f| match filter { + // Filter::FunctionInLines(..) + // | Filter::FunctionWithParent(_) + // | Filter::FunctionInBlock(_) + // | Filter::Directory(_) + // | Filter::FileAbsolute(_) + // | Filter::FileRelative(_) => f.filter_by(filter).is_ok(), + // Filter::CommitHash(commit_hash) => &f.commit_hash == commit_hash, + // Filter::Date(date) => &f.date.to_rfc2822() == date, + // Filter::DateRange(start, end) => { + // let start = match DateTime::parse_from_rfc2822(start) { + // Ok(date) => date, + // Err(_) => return false, + // }; + // let end = match DateTime::parse_from_rfc2822(end) { + // Ok(date) => date, + // Err(_) => return false, + // }; + // f.date >= start || f.date <= end + // } + // Filter::Author(author) => &f.author == author, + // Filter::AuthorEmail(email) => &f.email == email, + // Filter::Message(message) => f.message.contains(message), + // Filter::None => true, + // }) + // .cloned() + // .collect(); + + // if vec.is_empty() { + // return Err("No history found for the filter")?; + // } + // Ok(Self { + // commit_history: vec, + // name: self.name.clone(), + // current_pos: 0, + // current_iter_pos: 0, + // }) + todo!() } } -impl fmt::Display for FunctionHistory { +impl fmt::Display for FunctionHistory { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "{}", self.commit_history[self.current_pos])?; Ok(()) } } -impl Iterator for FunctionHistory { - type Item = CommitFunctions; +impl Iterator for FunctionHistory { + type Item = CommitFunctions; fn next(&mut self) -> Option { self.commit_history .get(self.current_iter_pos) @@ -391,12 +404,12 @@ pub enum Directions { Both, } -trait ErrorToOption { - fn to_option(self) -> Option; +trait ErrorToOption { + fn to_option(self) -> Option; } -impl ErrorToOption for Result> { - fn to_option(self) -> Option { +impl ErrorToOption for Result> { + fn to_option(self) -> Option { match self { Ok(t) => Some(t), Err(_) => None, From a2c14a181305414ac4892e667e65494c2a012958 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Sun, 2 Oct 2022 20:49:32 +0000 Subject: [PATCH 009/172] update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12f67c01..8098c45e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,10 @@ All notable changes to this project will be documented in this file. - Trying to fix changelog +### Lib + +- Moved away from using mostly enerics to using enums + ### Tui - Saving search history to a file now From b37aa91ec815dc84fa7e10d286da18a3bb92ab4d Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 2 Oct 2022 19:05:00 -0400 Subject: [PATCH 010/172] testing python --- git-function-history-lib/src/test_functions.py | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 git-function-history-lib/src/test_functions.py diff --git a/git-function-history-lib/src/test_functions.py b/git-function-history-lib/src/test_functions.py new file mode 100644 index 00000000..60bd13a9 --- /dev/null +++ b/git-function-history-lib/src/test_functions.py @@ -0,0 +1,2 @@ +def empty_test(): + print("This is an empty test") \ No newline at end of file From f60ef00be9a0677122ed2c46bd4db83231d16a80 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 2 Oct 2022 19:25:03 -0400 Subject: [PATCH 011/172] whyu --- git-function-history-lib/src/test_functions.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/git-function-history-lib/src/test_functions.py b/git-function-history-lib/src/test_functions.py index 60bd13a9..c29ed9f1 100644 --- a/git-function-history-lib/src/test_functions.py +++ b/git-function-history-lib/src/test_functions.py @@ -1,2 +1,12 @@ +from ctypes.wintypes import PINT + + +PINT = 1 + def empty_test(): - print("This is an empty test") \ No newline at end of file + print("This is an empty test") + +def test_with_assert(): + assert True + +passing_test = test_with_assert \ No newline at end of file From ce8cddb9efe560907a046318680445798c1a344f Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 2 Oct 2022 19:35:51 -0400 Subject: [PATCH 012/172] lib: python works besides for one edge case when the function is the last node todo: need to clean up, document, optimze espicaly cause the rust is taking too long reimplent filters implenmt c support --- cargo-function-history/src/app/mod.rs | 34 +++-- cargo-function-history/src/main.rs | 7 +- function_history_backend_thread/src/lib.rs | 4 +- function_history_backend_thread/src/types.rs | 4 +- git-function-history-gui/src/lib.rs | 16 ++- git-function-history-lib/src/languages/c.rs | 14 +-- git-function-history-lib/src/languages/mod.rs | 21 +++- .../src/languages/python.rs | 11 +- .../src/languages/rust.rs | 2 - git-function-history-lib/src/lib.rs | 116 ++++++++++++++---- git-function-history-lib/src/types.rs | 111 ++++++++++++----- 11 files changed, 243 insertions(+), 97 deletions(-) diff --git a/cargo-function-history/src/app/mod.rs b/cargo-function-history/src/app/mod.rs index 7d90ccab..ce379eab 100644 --- a/cargo-function-history/src/app/mod.rs +++ b/cargo-function-history/src/app/mod.rs @@ -5,7 +5,12 @@ use crate::{app::actions::Action, keys::Key}; use function_history_backend_thread::types::{ CommandResult, FilterType, FullCommand, ListType, Status, }; -use git_function_history::{BlockType, FileType, Filter}; +use git_function_history::{ + languages::Language, + // BlockType, + FileType, + Filter, +}; use std::{ fs, io::{Read, Write}, @@ -200,15 +205,15 @@ impl App { None } } - "block" => { - if let Some(block) = iter.next() { - Some(Filter::FunctionInBlock(BlockType::from_string(block))) - } else { - self.status = - Status::Error("No block type given".to_string()); - None - } - } + // "block" => { + // if let Some(block) = iter.next() { + // Some(Filter::FunctionInBlock(BlockType::from_string(block))) + // } else { + // self.status = + // Status::Error("No block type given".to_string()); + // None + // } + // } "date-range" => { if let Some(start) = iter.next() { if let Some(end) = iter.next() { @@ -315,6 +320,7 @@ impl App { name.to_string(), FileType::None, Filter::None, + Language::Rust, )) } Some(thing) => match thing { @@ -388,7 +394,12 @@ impl App { None => Filter::None, }; - Some(FullCommand::Search(name.to_string(), file_type, filter)) + Some(FullCommand::Search( + name.to_string(), + file_type, + filter, + Language::Rust, + )) } "date" | "commit" | "date range" => { let filter = match thing { @@ -439,6 +450,7 @@ impl App { name.to_string(), FileType::None, filter, + Language::Rust, )) } _ => { diff --git a/cargo-function-history/src/main.rs b/cargo-function-history/src/main.rs index 6a1b9638..286f7e1b 100644 --- a/cargo-function-history/src/main.rs +++ b/cargo-function-history/src/main.rs @@ -16,7 +16,12 @@ fn main() -> Result<(), Box> { let status = match config.function_name { string if string.is_empty() => Status::Ok(None), string => { - tx_m.send(FullCommand::Search(string, config.file_type, config.filter))?; + tx_m.send(FullCommand::Search( + string, + config.file_type, + config.filter, + git_function_history::languages::Language::Rust, + ))?; Status::Loading } }; diff --git a/function_history_backend_thread/src/lib.rs b/function_history_backend_thread/src/lib.rs index 9768c8c4..a46187de 100644 --- a/function_history_backend_thread/src/lib.rs +++ b/function_history_backend_thread/src/lib.rs @@ -87,11 +87,11 @@ pub fn command_thread( }, } } - FullCommand::Search(name, file, filter) => { + FullCommand::Search(name, file, _filter, lang) => { if log { log::info!("Searching for {} in {:?}", name, file); } - match get_function_history(&name, &file, filter) { + match get_function_history(&name, &file, &lang) { Ok(functions) => { if log { log::info!("Found functions"); diff --git a/function_history_backend_thread/src/types.rs b/function_history_backend_thread/src/types.rs index 2fe81fa2..28e6c492 100644 --- a/function_history_backend_thread/src/types.rs +++ b/function_history_backend_thread/src/types.rs @@ -1,6 +1,6 @@ use std::fmt; -use git_function_history::{FileType, Filter, FunctionHistory}; +use git_function_history::{languages::Language, FileType, Filter, FunctionHistory}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Command { @@ -117,7 +117,7 @@ impl Default for Status { pub enum FullCommand { Filter(FilterType), List(ListType), - Search(String, FileType, Filter), + Search(String, FileType, Filter, Language), } #[derive(Debug, Clone)] diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index 9662c536..0f479313 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -13,7 +13,13 @@ use function_history_backend_thread::types::{ Command, CommandResult, FilterType, FullCommand, HistoryFilterType, ListType, Status, }; use git_function_history::{ - types::Directions, BlockType, CommitFunctions, FileType, Filter, FunctionHistory, + languages::Language, + types::Directions, + // BlockType, + CommitFunctions, + FileType, + Filter, + FunctionHistory, }; // TODO: stop cloning everyting and use references instead @@ -403,9 +409,10 @@ impl eframe::App for MyEguiApp { HistoryFilterType::DateRange(date1, date2) => Some( Filter::DateRange(date1.to_string(), date2.to_string()), ), - HistoryFilterType::FunctionInBlock(block) => Some( - Filter::FunctionInBlock(BlockType::from_string(block)), - ), + HistoryFilterType::FunctionInBlock(_block) => None, + // Some( + // Filter::FunctionInBlock(BlockType::from_string(block)), + // ), HistoryFilterType::FunctionInLines(line1, line2) => { let fn_in_lines = ( match line1.parse::() { @@ -575,6 +582,7 @@ impl eframe::App for MyEguiApp { self.input_buffer.clone(), self.file_type.clone(), self.filter.clone(), + Language::Rust, )) .unwrap(); } diff --git a/git-function-history-lib/src/languages/c.rs b/git-function-history-lib/src/languages/c.rs index 0ba3030f..c0fde261 100644 --- a/git-function-history-lib/src/languages/c.rs +++ b/git-function-history-lib/src/languages/c.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, error::Error}; +use std::collections::HashMap; use super::FunctionResult; #[derive(Debug, Clone)] @@ -34,9 +34,9 @@ impl Function { impl super::Function for Function { fn fmt_with_context( &self, - f: &mut std::fmt::Formatter<'_>, - previous: Option<&Self>, - next: Option<&Self>, + _f: &mut std::fmt::Formatter<'_>, + _previous: Option<&Self>, + _next: Option<&Self>, ) -> std::fmt::Result { todo!() } @@ -56,9 +56,9 @@ pub struct ParentFunction { } pub(crate) fn find_function_in_commit( - commit: &str, - file_path: &str, - name: &str, + _commit: &str, + _file_path: &str, + _name: &str, ) -> FunctionResult { todo!("find_function_in_commit") } diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index b5b0a6f7..26f45b97 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -1,7 +1,5 @@ use std::{collections::HashMap, error::Error, fmt}; - -use crate::{File, Filter}; - +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Language { /// The python language Python, @@ -11,12 +9,23 @@ pub enum Language { C, } +impl Language { + pub fn from_string(s: &str) -> Result> { + match s { + "python" => Ok(Self::Python), + "rust" => Ok(Self::Rust), + "c" => Ok(Self::C), + _ => Err(format!("Unknown language: {}", s))?, + } + } +} + impl fmt::Display for Language { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Language::Python => write!(f, "python"), - Language::Rust => write!(f, "rust"), - Language::C => write!(f, "c"), + Self::Python => write!(f, "python"), + Self::Rust => write!(f, "rust"), + Self::C => write!(f, "c"), } } } diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 6899b984..d9f3e816 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -6,10 +6,6 @@ use rustpython_parser::{ parser, }; -use crate::File; - -use super::FunctionResult; - #[derive(Debug, Clone)] pub struct Function { pub(crate) name: String, @@ -145,11 +141,12 @@ pub(crate) fn find_function_in_commit( name: &str, ) -> Result, Box> { let file_contents = crate::find_file_in_commit(commit, file_path)?; + let ast = parser::parse_program(&file_contents)?; let mut functions = vec![]; let mut last = None; for stmt in ast.statements { - get_functions(stmt, &mut functions, "baz", &mut last, &mut None); + get_functions(stmt, &mut functions, name, &mut last, &mut None); } let mut starts = file_contents .match_indices('\n') @@ -194,6 +191,9 @@ pub(crate) fn find_function_in_commit( new.push(new_func); } } + if new.is_empty() { + Err("No function found")?; + } Ok(new) } @@ -243,6 +243,7 @@ fn get_functions<'a>( std::mem::swap(last, &mut new); functions.push((new.0, (new.1, stmt.location))); } else { + // TODO: figure out if its the last node if so then we can push it here otherwise we need to wait for the next node *last_found_fn = Some((stmt.node, stmt.location)); } } diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 58f81313..45c9b40f 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -5,8 +5,6 @@ use ra_ap_syntax::{ AstNode, SourceFile, SyntaxKind, }; -use super::FunctionResult; - /// This holds the information about a single function each commit will have multiple of these. #[derive(Debug, Clone)] pub struct Function { diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 575c23f8..acf86f5a 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -18,7 +18,7 @@ pub mod languages; /// Different types that can extracted from the result of `get_function_history`. pub mod types; -use languages::{python, rust, Function}; +use languages::rust; #[cfg(feature = "parallel")] use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; @@ -185,8 +185,22 @@ pub fn get_function_history( let err = "no history found".to_string(); // check if file is a rust file if let FileType::Absolute(path) | FileType::Relative(path) = &file { - if !path.ends_with(".rs") { - Err("file is not a rust file")?; + match langs { + Language::C => { + if !path.ends_with(".c") || !path.ends_with(".h") { + Err("file is not a c file")?; + } + } + Language::Python => { + if !path.ends_with(".py") { + Err("file is not a python file")?; + } + } + Language::Rust => { + if !path.ends_with(".rs") { + Err("file is not a rust file")?; + } + } } } #[cfg(feature = "parallel")] @@ -196,24 +210,10 @@ pub fn get_function_history( file_history.commit_history = t .filter_map(|commit| match &file { FileType::Absolute(path) => { - match find_function_in_commit(commit.0, path, name, langs) { - Ok(contents) => Some(CommitFunctions::new( - commit.0.to_string(), - vec![File::new(path.to_string(), contents)], - commit.1, - commit.2.to_string(), - commit.3.to_string(), - commit.4.to_string(), - )), - Err(_) => None, - } - } - - FileType::Relative(_) => { - match find_function_in_commit_with_filetype(commit.0, name, file, langs) { + match find_function_in_commit(commit.0, path, name, *langs) { Ok(contents) => Some(CommitFunctions::new( commit.0.to_string(), - contents, + vec![contents], commit.1, commit.2.to_string(), commit.3.to_string(), @@ -223,8 +223,8 @@ pub fn get_function_history( } } - FileType::None | FileType::Directory(_) => { - match find_function_in_commit_with_filetype(commit.0, name, file, langs) { + FileType::Relative(_) | FileType::None | FileType::Directory(_) => { + match find_function_in_commit_with_filetype(commit.0, name, file, *langs) { Ok(contents) => Some(CommitFunctions::new( commit.0.to_string(), contents, @@ -282,7 +282,7 @@ fn find_function_in_commit_with_filetype( commit: &str, name: &str, filetype: &FileType, - langs: &Language, + langs: Language, ) -> Result, Box> { // get a list of all the files in the repository let mut files = Vec::new(); @@ -306,8 +306,23 @@ fn find_function_in_commit_with_filetype( } } FileType::None => { - if file.ends_with(".rs") { - files.push(file); + match langs { + Language::C => { + if file.ends_with(".c") || file.ends_with(".h") { + files.push(file); + } + } + Language::Python => { + if file.ends_with(".py") { + // panic!("{:?}", file); + files.push(file); + } + } + Language::Rust => { + if file.ends_with(".rs") { + files.push(file); + } + } } } _ => {} @@ -321,7 +336,7 @@ fn find_function_in_commit_with_filetype( let returns: Vec = t .filter_map( |file| match find_function_in_commit(commit, file, name, langs) { - Ok(functions) => Some(File::new((*file).to_string(), functions)), + Ok(functions) => Some(functions), Err(_) => None, }, ) @@ -332,6 +347,37 @@ fn find_function_in_commit_with_filetype( Ok(returns) } +fn find_function_in_commit( + commit: &str, + file_path: &str, + name: &str, + langs: Language, +) -> Result> { + match langs { + Language::Rust => { + let functions = rust::find_function_in_commit(commit, file_path, name)?; + Ok(File::new( + file_path.to_string(), + types::FileType::Rust(functions), + )) + } + Language::C => { + let functions = languages::c::find_function_in_commit(commit, file_path, name)?; + Ok(File::new( + file_path.to_string(), + types::FileType::C(functions), + )) + } + Language::Python => { + let functions = languages::python::find_function_in_commit(commit, file_path, name)?; + Ok(File::new( + file_path.to_string(), + types::FileType::Python(functions), + )) + } + } +} + trait UwrapToError { fn unwrap_to_error(self, message: &str) -> Result>; } @@ -451,4 +497,24 @@ mod tests { } assert!(output.is_ok()); } + + #[test] + fn python() { + let now = Utc::now(); + let output = get_function_history( + "empty_test", + &FileType::Relative("src/test_functions.py".to_string()), + // Filter::None, + &languages::Language::Python, + ); + let after = Utc::now() - now; + println!("time taken: {}", after.num_seconds()); + match &output { + Ok(functions) => { + println!("{}", functions); + } + Err(e) => println!("{}", e), + } + assert!(output.is_ok()); + } } diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index b209da7a..1ff55e7e 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -1,10 +1,10 @@ use chrono::{DateTime, FixedOffset}; #[cfg(feature = "parallel")] -use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; +use rayon::prelude::{ParallelIterator}; use std::{collections::HashMap, error::Error, fmt}; use crate::{ - languages::{c, python, rust, Function, Language}, + languages::{c, python, rust, Function}, Filter, }; @@ -13,13 +13,13 @@ use crate::{ pub struct File { /// The name of the file pub(crate) name: String, - pub(crate) functions: Vec, + pub(crate) functions: FileType, pub(crate) current_pos: usize, } impl File { /// Create a new file with the given name and functions - pub fn new(name: String, functions: Vec) -> Self { + pub fn new(name: String, functions: FileType) -> Self { Self { name, functions, @@ -28,49 +28,96 @@ impl File { } /// This is used to get the functions in the file - pub const fn get_functions(&self) -> &Vec { + pub const fn get_functions(&self) -> &FileType { &self.functions } /// This is used to get the functions in the file (mutable) - pub fn get_functions_mut(&mut self) -> &mut Vec { + pub fn get_functions_mut(&mut self) -> &mut FileType { &mut self.functions } - /// This is will get the current function in the file - pub fn get_current_function(&self) -> Option<&FileType> { - self.functions.get(self.current_pos) - } + // /// This is will get the current function in the file + // pub fn get_current_function(&self) -> Option<&FileType> { + // self.functions.get(self.current_pos) + // } - /// This is will get the current function in the file (mutable) - pub fn get_current_function_mut(&mut self) -> Option<&mut FileType> { - self.functions.get_mut(self.current_pos) - } -} - -impl Iterator for File { - type Item = FileType; - fn next(&mut self) -> Option { - // get the current function without removing it - let function = self.functions.get(self.current_pos).cloned(); - self.current_pos += 1; - function - } + // /// This is will get the current function in the file (mutable) + // pub fn get_current_function_mut(&mut self) -> Option<&mut FileType> { + // self.functions.get_mut(self.current_pos) + // } } impl fmt::Display for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.name) + // write!(f, "{}", self.name) + match &self.functions { + FileType::Python(python) => { + for (i, function) in python.iter().enumerate() { + write!( + f, + "{}", + match i { + 0 => "", + _ => "\n...\n", + }, + )?; + let previous = match i { + 0 => None, + _ => python.get(i - 1), + }; + let next = python.get(i + 1); + function.fmt_with_context(f, previous, next)?; + } + } + FileType::Rust(rust) => { + for (i, function) in rust.iter().enumerate() { + write!( + f, + "{}", + match i { + 0 => "", + _ => "\n...\n", + }, + )?; + let previous = match i { + 0 => None, + _ => rust.get(i - 1), + }; + let next = rust.get(i + 1); + function.fmt_with_context(f, previous, next)?; + } + } + FileType::C(c) => { + for (i, function) in c.iter().enumerate() { + write!( + f, + "{}", + match i { + 0 => "", + _ => "\n...\n", + }, + )?; + let previous = match i { + 0 => None, + _ => c.get(i - 1), + }; + let next = c.get(i + 1); + function.fmt_with_context(f, previous, next)?; + } + } + }; + Ok(()) } } #[derive(Debug, Clone)] pub enum FileType { /// The python language - Python(python::Function), + Python(Vec), /// The rust language - Rust(rust::Function), + Rust(Vec), /// c language - C(c::Function), + C(Vec), } /// This holds information like date and commit `commit_hash` and also the list of function found in the commit. @@ -138,12 +185,12 @@ impl CommitFunctions { } /// returns the current file - pub fn get_file(&self) -> &File { + pub fn get_file(&self) -> &File { &self.files[self.current_pos] } /// returns the current file (mutable) - pub fn get_file_mut(&mut self) -> &mut File { + pub fn get_file_mut(&mut self) -> &mut File { &mut self.files[self.current_pos] } @@ -160,7 +207,7 @@ impl CommitFunctions { /// returns a new `CommitFunctions` by filtering the current one by the filter specified (does not modify the current one). /// /// valid filters are: `Filter::FunctionInBlock`, `Filter::FunctionInLines`, `Filter::FunctionWithParent`, and `Filter::FileAbsolute`, `Filter::FileRelative`, and `Filter::Directory`. - pub fn filter_by(&self, filter: &Filter) -> Result> { + pub fn filter_by(&self, _filter: &Filter) -> Result> { // let mut vec = Vec::new(); // for f in &self.files { // match filter { @@ -324,7 +371,7 @@ impl FunctionHistory { /// /// history.filter_by(Filter::Directory("app".to_string())).unwrap(); /// ``` - pub fn filter_by(&self, filter: &Filter) -> Result> { + pub fn filter_by(&self, _filter: &Filter) -> Result> { // #[cfg(feature = "parallel")] // let t = self.commit_history.par_iter(); // #[cfg(not(feature = "parallel"))] From 5df85be96e01b32c29fdd5131b6a3d562b4428c8 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Sun, 2 Oct 2022 23:36:32 +0000 Subject: [PATCH 013/172] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8098c45e..3a3eeae0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ All notable changes to this project will be documented in this file. ### Lib - Moved away from using mostly enerics to using enums +- Python works besides for one edge case when the function is the last node ### Tui From 04d4403be7e267685430a15816d1f1a57b5477ea Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 3 Oct 2022 14:33:52 -0400 Subject: [PATCH 014/172] blah blah --- git-function-history-lib/src/test_functions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-function-history-lib/src/test_functions.rs b/git-function-history-lib/src/test_functions.rs index e76719ff..e041e840 100644 --- a/git-function-history-lib/src/test_functions.rs +++ b/git-function-history-lib/src/test_functions.rs @@ -53,7 +53,7 @@ implTest { pub trait super_trait { fn super_trait_method(&self); - fn empty_test() -> String where T: super_trait; + fn empty_test() -> String where T: super_trait; } impl <'a, t> super_trait for t { From bd8bfc7fa1f138b8a121c69c26c34a17f3e30539 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 3 Oct 2022 14:47:40 -0400 Subject: [PATCH 015/172] more messing with testing --- git-function-history-lib/src/test_functions.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/git-function-history-lib/src/test_functions.rs b/git-function-history-lib/src/test_functions.rs index e041e840..412209f7 100644 --- a/git-function-history-lib/src/test_functions.rs +++ b/git-function-history-lib/src/test_functions.rs @@ -111,7 +111,9 @@ pub fn function_within(t: String) -> Result> { } pub struct Test2 -where T: super_trait { +where +T: +super_trait { pub contents: String, pub history: Vec, } From d15e50bbcb2878e5862a513b8ba5452d68934bee Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 3 Oct 2022 14:53:22 -0400 Subject: [PATCH 016/172] more messings --- git-function-history-lib/src/test_functions.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/git-function-history-lib/src/test_functions.rs b/git-function-history-lib/src/test_functions.rs index 412209f7..5393ad30 100644 --- a/git-function-history-lib/src/test_functions.rs +++ b/git-function-history-lib/src/test_functions.rs @@ -110,12 +110,12 @@ pub fn function_within(t: String) -> Result> { empty_test(t) } -pub struct Test2 +pub struct Test2 where -T: +A: super_trait { pub contents: String, - pub history: Vec, + pub history: Vec, } impl Test2 From 279479d6a5b6261d8794cd7b73c9942a312f4bc1 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 3 Oct 2022 14:55:16 -0400 Subject: [PATCH 017/172] maybe mssing in wrong spot --- git-function-history-lib/src/test_functions.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/git-function-history-lib/src/test_functions.rs b/git-function-history-lib/src/test_functions.rs index 5393ad30..2ef0ef12 100644 --- a/git-function-history-lib/src/test_functions.rs +++ b/git-function-history-lib/src/test_functions.rs @@ -118,8 +118,10 @@ super_trait { pub history: Vec, } -impl Test2 -where T: super_trait { +impl Test2 +where +A: +super_trait { pub fn empty_test<'a>() { println!("empty test"); } From b5d626ad487dfd77d094f3d697a7e0cc452a3498 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 3 Oct 2022 15:55:49 -0400 Subject: [PATCH 018/172] more messibng --- git-function-history-lib/src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 1ff55e7e..78eb0da8 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -125,7 +125,7 @@ pub enum FileType { pub struct CommitFunctions { commit_hash: String, files: Vec, - date: DateTime, + pub (crate )date: DateTime, current_iter_pos: usize, current_pos: usize, author: String, From 9a45620d6e6a34b937e3db5e5b006c3ddd87c77a Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 3 Oct 2022 16:05:12 -0400 Subject: [PATCH 019/172] df --- git-function-history-lib/src/test_functions.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/git-function-history-lib/src/test_functions.rs b/git-function-history-lib/src/test_functions.rs index 2ef0ef12..70c9a900 100644 --- a/git-function-history-lib/src/test_functions.rs +++ b/git-function-history-lib/src/test_functions.rs @@ -118,10 +118,9 @@ super_trait { pub history: Vec, } -impl Test2 -where -A: -super_trait { +impl Test2 +where A: +super_trait + Clone{ pub fn empty_test<'a>() { println!("empty test"); } From eb2cfa0a577dba5ef6fd5a2aa9c2a63cbeeef312 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 3 Oct 2022 16:15:32 -0400 Subject: [PATCH 020/172] shoulkd just move this file to ints own repo --- git-function-history-lib/src/test_functions.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-function-history-lib/src/test_functions.rs b/git-function-history-lib/src/test_functions.rs index 70c9a900..0db69235 100644 --- a/git-function-history-lib/src/test_functions.rs +++ b/git-function-history-lib/src/test_functions.rs @@ -53,7 +53,7 @@ implTest { pub trait super_trait { fn super_trait_method(&self); - fn empty_test() -> String where T: super_trait; + fn empty_test() -> String where T: super_trait; } impl <'a, t> super_trait for t { @@ -62,7 +62,7 @@ impl <'a, t> super_trait for t { /* dff gdg */ - fn empty_test() -> String where T: super_trait { + fn empty_test() -> String where T: super_trait + Clone { String::from("fn empty_test() "); fn broken() { r#"#"}"#; From 59b222e8b7f17c7654a2110f07dad3482caac8e2 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 3 Oct 2022 16:20:19 -0400 Subject: [PATCH 021/172] more testing --- git-function-history-lib/src/test_functions.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/git-function-history-lib/src/test_functions.rs b/git-function-history-lib/src/test_functions.rs index 0db69235..61b9372e 100644 --- a/git-function-history-lib/src/test_functions.rs +++ b/git-function-history-lib/src/test_functions.rs @@ -120,7 +120,10 @@ super_trait { impl Test2 where A: -super_trait + Clone{ +super_trait + Clone, +T: super + +{ pub fn empty_test<'a>() { println!("empty test"); } From b57600fc113fe91b2eb46e230669ea38aa5b2c6d Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 3 Oct 2022 16:49:48 -0400 Subject: [PATCH 022/172] lib: non proggraming languge (pl) filters addded back pl filter will be defined the pl rust file for that languge and the joind together via an enum --- cargo-function-history/src/app/mod.rs | 3 +- function_history_backend_thread/src/lib.rs | 4 +- git-function-history-gui/src/lib.rs | 3 +- .../src/languages/python.rs | 12 ++- .../src/languages/rust.rs | 45 ++++++--- git-function-history-lib/src/lib.rs | 98 ++++++++++--------- 6 files changed, 98 insertions(+), 67 deletions(-) diff --git a/cargo-function-history/src/app/mod.rs b/cargo-function-history/src/app/mod.rs index ce379eab..f669350b 100644 --- a/cargo-function-history/src/app/mod.rs +++ b/cargo-function-history/src/app/mod.rs @@ -198,7 +198,8 @@ impl App { } "parent" => { if let Some(parent) = iter.next() { - Some(Filter::FunctionWithParent(parent.to_string())) + // Some(Filter::FunctionWithParent(parent.to_string())) + None } else { self.status = Status::Error("No parent function given".to_string()); diff --git a/function_history_backend_thread/src/lib.rs b/function_history_backend_thread/src/lib.rs index a46187de..cbd7d0d3 100644 --- a/function_history_backend_thread/src/lib.rs +++ b/function_history_backend_thread/src/lib.rs @@ -87,11 +87,11 @@ pub fn command_thread( }, } } - FullCommand::Search(name, file, _filter, lang) => { + FullCommand::Search(name, file, filter, lang) => { if log { log::info!("Searching for {} in {:?}", name, file); } - match get_function_history(&name, &file, &lang) { + match get_function_history(&name, &file, &filter, &lang) { Ok(functions) => { if log { log::info!("Found functions"); diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index 0f479313..9e46ea85 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -438,7 +438,8 @@ impl eframe::App for MyEguiApp { )) } HistoryFilterType::FunctionInFunction(function) => { - Some(Filter::FunctionWithParent(function.to_string())) + // Some(Filter::FunctionWithParent(function.to_string())) + None } HistoryFilterType::FileAbsolute(file) => { Some(Filter::FileAbsolute(file.to_string())) diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index d9f3e816..5198f25f 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -163,7 +163,8 @@ pub(crate) fn find_function_in_commit( // get the function body based on the location let start = func.1 .0.row(); let end = func.1 .1.row(); - let start = map[&(start - 1)]; + let start = map[&(start-1)]; + let end = map[&(end - 1)]; if let StatementType::FunctionDef { name, @@ -174,7 +175,14 @@ pub(crate) fn find_function_in_commit( .. } = func.0 { - let body = file_contents[*start..*end].to_string(); + let mut start_s = func.1 .0.row(); + let body = file_contents[*start..*end].trim_start_matches('\n').to_string().lines().map(|l| { + + let t= format!("{}: {}\n", start_s, l,); + start_s += 1; + t + }) + .collect::(); let new_func = Function { name: name.to_string(), returns: returns.as_ref().map(|x| x.name().to_string()), diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 45c9b40f..8a645f51 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -22,7 +22,7 @@ pub struct Function { /// The generic types of the function pub(crate) generics: Vec, /// The arguments of the function - pub(crate) arguments: Vec, + pub(crate) arguments: HashMap, /// The return type of the function pub(crate) return_type: Option, /// The functions atrributes @@ -116,7 +116,7 @@ impl super::Function for Function { map.insert("block", format!("{}", block.block_type)); } map.insert("generics", self.generics.join(",")); - map.insert("arguments", self.arguments.join(",")); + map.insert("arguments", self.arguments.iter().map(|(k, v)| format!("{}: {}", k, v)).collect::>().join(",")); map.insert("lifetime generics", self.lifetime.join(",")); map.insert("attributes", self.attributes.join(",")); map.insert("doc comments", self.doc_comments.join(",")); @@ -179,7 +179,7 @@ pub struct FunctionBlock { /// The generic types of the function pub(crate) generics: Vec, /// The arguments of the function - pub(crate) arguments: Vec, + pub(crate) arguments: HashMap, /// The return type of the function pub(crate) return_type: Option, /// the function atrributes @@ -197,7 +197,7 @@ impl FunctionBlock { map.insert("signature".to_string(), self.top.clone()); map.insert("bottom".to_string(), self.bottom.clone()); map.insert("generics".to_string(), self.generics.join(",")); - map.insert("arguments".to_string(), self.arguments.join(",")); + map.insert("arguments".to_string(), self.arguments.iter().map(|(k, v)| format!("{}: {}", k, v)).collect::>().join(",")); map.insert("lifetime generics".to_string(), self.lifetime.join(",")); map.insert("attributes".to_string(), self.attributes.join(",")); map.insert("doc comments".to_string(), self.doc_comments.join(",")); @@ -380,12 +380,12 @@ pub(crate) fn find_function_in_commit( bottom: stuff.1 .1, lines: (stuff.0 .0, stuff.0 .1), return_type: function.ret_type().map(|ty| ty.to_string()), - arguments: match function.param_list() { + arguments: match f.param_list() { Some(args) => args - .params() - .map(|arg| arg.to_string()) - .collect::>(), - None => Vec::new(), + .params() + .filter_map(|arg| arg.to_string().rsplit_once(": ").map(|x| (x.0.to_string(), x.1.to_string()))) + .collect::>() , + None => HashMap::new(), }, attributes: attr.1, doc_comments: attr.0, @@ -417,10 +417,10 @@ pub(crate) fn find_function_in_commit( return_type: f.ret_type().map(|ty| ty.to_string()), arguments: match f.param_list() { Some(args) => args - .params() - .map(|arg| arg.to_string()) - .collect::>(), - None => Vec::new(), + .params() + .filter_map(|arg| arg.to_string().rsplit_once(": ").map(|x| (x.0.to_string(), x.1.to_string()))) + .collect::>() , + None => HashMap::new(), }, lifetime: generics.1, generics: generics.0, @@ -517,6 +517,7 @@ fn get_stuff( } fn get_genrerics_and_lifetime(block: &T) -> (Vec, Vec) { + // TODO: map trait bounds from where clauses to the generics and also use type_or_const_params match block.generic_param_list() { None => (vec![], vec![]), Some(gt) => ( @@ -542,3 +543,21 @@ fn get_doc_comments_and_attrs(block: &T) -> (Vec, Vec .collect::>(), ) } + + +pub enum Filter { + /// when you want to filter by function that are in a specific block (impl, trait, extern) + FunctionInBlock(Block), + /// when you want filter by a function that has a parent function of a specific name + FunctionWithParent(String), + /// when you want to filter by a function that has a has a specific return type + FunctionWithReturnType(String), + /// when you want to filter by a function that has a specific parameter type + FunctionWithParameterType(String), + /// when you want to filter by a function that has a specific lifetime + FunctionWithLifetime(String), + /// when you want to filter by a function that has a specific generic with name + FunctionWithGeneric(String), + /// when you want to filter by a function that has a specific attribute + FunctionWithAttribute(String), +} \ No newline at end of file diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index acf86f5a..4f6fa763 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -56,12 +56,10 @@ pub enum Filter { FileRelative(String), /// When you want to filter only files in a specific directory Directory(String), - /// when you want to filter by function that are in a specific block (impl, trait, extern) - // FunctionInBlock(Block), + /// when you want to filter by function that are in between specific lines FunctionInLines(usize, usize), - /// when you want filter by a function that has a parent function of a specific name - FunctionWithParent(String), + /// when you want to filter by a any commit author name that contains a specific string Author(String), /// when you want to filter by a any commit author email that contains a specific string @@ -106,6 +104,7 @@ pub enum Filter { pub fn get_function_history( name: &str, file: &FileType, + filter: &Filter, langs: &languages::Language, ) -> Result> { // chack if name is empty @@ -119,40 +118,40 @@ pub fn get_function_history( command.arg("log"); command.arg("--pretty=%H;%aD;%aN;%aE;%s"); command.arg("--date=rfc2822"); - // match filter { - // Filter::CommitHash(hash) => { - // command.arg(hash); - // command.arg("-n"); - // command.arg("1"); - // } - // Filter::Date(date) => { - // command.arg("--since"); - // command.arg(date); - // command.arg("--max-count=1"); - // } - // Filter::DateRange(start, end) => { - // command.arg("--since"); - // command.arg(start); - // command.arg("--until"); - // command.arg(end); - // } - // Filter::Author(author) => { - // command.arg("--author"); - // command.arg(author); - // } - // Filter::AuthorEmail(email) => { - // command.arg("--author"); - // command.arg(email); - // } - // Filter::Message(message) => { - // command.arg("--grep"); - // command.arg(message); - // } - // Filter::None => {} - // _ => { - // Err("filter not supported")?; - // } - // } + match filter { + Filter::CommitHash(hash) => { + command.arg(hash); + command.arg("-n"); + command.arg("1"); + } + Filter::Date(date) => { + command.arg("--since"); + command.arg(date); + command.arg("--max-count=1"); + } + Filter::DateRange(start, end) => { + command.arg("--since"); + command.arg(start); + command.arg("--until"); + command.arg(end); + } + Filter::Author(author) => { + command.arg("--author"); + command.arg(author); + } + Filter::AuthorEmail(email) => { + command.arg("--author"); + command.arg(email); + } + Filter::Message(message) => { + command.arg("--grep"); + command.arg(message); + } + Filter::None => {} + _ => { + Err("filter not supported")?; + } + } let output = command.output()?; if !output.stderr.is_empty() { return Err(String::from_utf8(output.stderr)?)?; @@ -402,7 +401,7 @@ mod tests { let output = get_function_history( "empty_test", &FileType::Relative("src/test_functions.rs".to_string()), - // Filter::None, + &Filter::None, &languages::Language::Rust, ); let after = Utc::now() - now; @@ -420,7 +419,7 @@ mod tests { let output = get_function_history( "empty_test", &FileType::Absolute("src/test_functions.rs".to_string()), - // Filter::None, + &Filter::None, &languages::Language::Rust, ); // assert that err is "not git is not installed" @@ -434,7 +433,7 @@ mod tests { let output = get_function_history( "Not_a_function", &FileType::Absolute("src/test_functions.rs".to_string()), - // Filter::None, + &Filter::None, &languages::Language::Rust, ); match &output { @@ -449,7 +448,7 @@ mod tests { let output = get_function_history( "empty_test", &FileType::Absolute("src/test_functions.txt".to_string()), - // Filter::None, + &Filter::None, &languages::Language::Rust, ); assert!(output.is_err()); @@ -461,10 +460,10 @@ mod tests { let output = get_function_history( "empty_test", &FileType::None, - // Filter::DateRange( - // "17 Aug 2022 11:27:23 -0400".to_owned(), - // "19 Aug 2022 23:45:52 +0000".to_owned(), - // ), + &Filter::DateRange( + "27 Sep 2022 11:27:23 -0400".to_owned(), + "04 Oct 2022 23:45:52 +0000".to_owned(), + ), &languages::Language::Rust, ); let after = Utc::now() - now; @@ -484,7 +483,7 @@ mod tests { let output = get_function_history( "empty_test", &FileType::None, - // Filter::None, + &Filter::None, &languages::Language::Rust, ); let after = Utc::now() - now; @@ -504,7 +503,10 @@ mod tests { let output = get_function_history( "empty_test", &FileType::Relative("src/test_functions.py".to_string()), - // Filter::None, + &Filter::DateRange( + "03 Oct 2022 11:27:23 -0400".to_owned(), + "04 Oct 2022 23:45:52 +0000".to_owned(), + ), &languages::Language::Python, ); let after = Utc::now() - now; From 5c6e57aaf8f8b53cbee15048585984e1065f475a Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Mon, 3 Oct 2022 20:50:19 +0000 Subject: [PATCH 023/172] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a3eeae0..b98ada18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ All notable changes to this project will be documented in this file. - Moved away from using mostly enerics to using enums - Python works besides for one edge case when the function is the last node +- Non proggraming languge (pl) filters addded back ### Tui From 986f47cb3f4b0e05775f48d0c564ac0d96ff146c Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 3 Oct 2022 16:56:26 -0400 Subject: [PATCH 024/172] cargo fmted and clipped the last commit. --- cargo-function-history/src/app/mod.rs | 2 +- git-function-history-gui/src/lib.rs | 2 +- .../src/languages/python.rs | 87 ++++--------------- .../src/languages/rust.rs | 43 ++++++--- git-function-history-lib/src/types.rs | 6 +- 5 files changed, 55 insertions(+), 85 deletions(-) diff --git a/cargo-function-history/src/app/mod.rs b/cargo-function-history/src/app/mod.rs index f669350b..d3046337 100644 --- a/cargo-function-history/src/app/mod.rs +++ b/cargo-function-history/src/app/mod.rs @@ -197,7 +197,7 @@ impl App { } } "parent" => { - if let Some(parent) = iter.next() { + if let Some(_parent) = iter.next() { // Some(Filter::FunctionWithParent(parent.to_string())) None } else { diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index 9e46ea85..e889dd59 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -437,7 +437,7 @@ impl eframe::App for MyEguiApp { fn_in_lines.1, )) } - HistoryFilterType::FunctionInFunction(function) => { + HistoryFilterType::FunctionInFunction(_function) => { // Some(Filter::FunctionWithParent(function.to_string())) None } diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 5198f25f..a78f2412 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -163,8 +163,8 @@ pub(crate) fn find_function_in_commit( // get the function body based on the location let start = func.1 .0.row(); let end = func.1 .1.row(); - let start = map[&(start-1)]; - + let start = map[&(start - 1)]; + let end = map[&(end - 1)]; if let StatementType::FunctionDef { name, @@ -176,13 +176,16 @@ pub(crate) fn find_function_in_commit( } = func.0 { let mut start_s = func.1 .0.row(); - let body = file_contents[*start..*end].trim_start_matches('\n').to_string().lines().map(|l| { - - let t= format!("{}: {}\n", start_s, l,); - start_s += 1; - t - }) - .collect::(); + let body = file_contents[*start..*end] + .trim_start_matches('\n') + .to_string() + .lines() + .map(|l| { + let t = format!("{}: {}\n", start_s, l,); + start_s += 1; + t + }) + .collect::(); let new_func = Function { name: name.to_string(), returns: returns.as_ref().map(|x| x.name().to_string()), @@ -255,37 +258,10 @@ fn get_functions<'a>( *last_found_fn = Some((stmt.node, stmt.location)); } } - StatementType::FunctionDef { body, .. } => { - fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); - fun_name1( - body, - functions, - lookup_name, - last_found_fn, - other_last_found_fn, - ); - } - StatementType::If { body, orelse, .. } => { - fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); - fun_name1( - body, - functions, - lookup_name, - last_found_fn, - other_last_found_fn, - ); - if let Some(stmts) = orelse { - fun_name1( - stmts, - functions, - lookup_name, - last_found_fn, - other_last_found_fn, - ); - } - } - StatementType::While { body, orelse, .. } => { + StatementType::If { body, orelse, .. } + | StatementType::While { body, orelse, .. } + | StatementType::For { body, orelse, .. } => { fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); fun_name1( body, @@ -304,26 +280,9 @@ fn get_functions<'a>( ); } } - StatementType::For { body, orelse, .. } => { - fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); - fun_name1( - body, - functions, - lookup_name, - last_found_fn, - other_last_found_fn, - ); - if let Some(stmts) = orelse { - fun_name1( - stmts, - functions, - lookup_name, - last_found_fn, - other_last_found_fn, - ); - } - } - StatementType::With { body, .. } => { + StatementType::FunctionDef { body, .. } + | StatementType::ClassDef { body, .. } + | StatementType::With { body, .. } => { fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); fun_name1( body, @@ -376,16 +335,6 @@ fn get_functions<'a>( ); } } - StatementType::ClassDef { body, .. } => { - fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); - fun_name1( - body, - functions, - lookup_name, - last_found_fn, - other_last_found_fn, - ); - } _ => { fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); } diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 8a645f51..f8d00547 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -116,7 +116,14 @@ impl super::Function for Function { map.insert("block", format!("{}", block.block_type)); } map.insert("generics", self.generics.join(",")); - map.insert("arguments", self.arguments.iter().map(|(k, v)| format!("{}: {}", k, v)).collect::>().join(",")); + map.insert( + "arguments", + self.arguments + .iter() + .map(|(k, v)| format!("{}: {}", k, v)) + .collect::>() + .join(","), + ); map.insert("lifetime generics", self.lifetime.join(",")); map.insert("attributes", self.attributes.join(",")); map.insert("doc comments", self.doc_comments.join(",")); @@ -197,7 +204,14 @@ impl FunctionBlock { map.insert("signature".to_string(), self.top.clone()); map.insert("bottom".to_string(), self.bottom.clone()); map.insert("generics".to_string(), self.generics.join(",")); - map.insert("arguments".to_string(), self.arguments.iter().map(|(k, v)| format!("{}: {}", k, v)).collect::>().join(",")); + map.insert( + "arguments".to_string(), + self.arguments + .iter() + .map(|(k, v)| format!("{}: {}", k, v)) + .collect::>() + .join(","), + ); map.insert("lifetime generics".to_string(), self.lifetime.join(",")); map.insert("attributes".to_string(), self.attributes.join(",")); map.insert("doc comments".to_string(), self.doc_comments.join(",")); @@ -382,9 +396,13 @@ pub(crate) fn find_function_in_commit( return_type: function.ret_type().map(|ty| ty.to_string()), arguments: match f.param_list() { Some(args) => args - .params() - .filter_map(|arg| arg.to_string().rsplit_once(": ").map(|x| (x.0.to_string(), x.1.to_string()))) - .collect::>() , + .params() + .filter_map(|arg| { + arg.to_string() + .rsplit_once(": ") + .map(|x| (x.0.to_string(), x.1.to_string())) + }) + .collect::>(), None => HashMap::new(), }, attributes: attr.1, @@ -417,9 +435,13 @@ pub(crate) fn find_function_in_commit( return_type: f.ret_type().map(|ty| ty.to_string()), arguments: match f.param_list() { Some(args) => args - .params() - .filter_map(|arg| arg.to_string().rsplit_once(": ").map(|x| (x.0.to_string(), x.1.to_string()))) - .collect::>() , + .params() + .filter_map(|arg| { + arg.to_string() + .rsplit_once(": ") + .map(|x| (x.0.to_string(), x.1.to_string())) + }) + .collect::>(), None => HashMap::new(), }, lifetime: generics.1, @@ -544,7 +566,6 @@ fn get_doc_comments_and_attrs(block: &T) -> (Vec, Vec ) } - pub enum Filter { /// when you want to filter by function that are in a specific block (impl, trait, extern) FunctionInBlock(Block), @@ -556,8 +577,8 @@ pub enum Filter { FunctionWithParameterType(String), /// when you want to filter by a function that has a specific lifetime FunctionWithLifetime(String), - /// when you want to filter by a function that has a specific generic with name + /// when you want to filter by a function that has a specific generic with name FunctionWithGeneric(String), /// when you want to filter by a function that has a specific attribute FunctionWithAttribute(String), -} \ No newline at end of file +} diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 78eb0da8..35891d02 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -1,6 +1,6 @@ use chrono::{DateTime, FixedOffset}; #[cfg(feature = "parallel")] -use rayon::prelude::{ParallelIterator}; +use rayon::prelude::ParallelIterator; use std::{collections::HashMap, error::Error, fmt}; use crate::{ @@ -19,7 +19,7 @@ pub struct File { impl File { /// Create a new file with the given name and functions - pub fn new(name: String, functions: FileType) -> Self { + pub const fn new(name: String, functions: FileType) -> Self { Self { name, functions, @@ -125,7 +125,7 @@ pub enum FileType { pub struct CommitFunctions { commit_hash: String, files: Vec, - pub (crate )date: DateTime, + pub(crate) date: DateTime, current_iter_pos: usize, current_pos: usize, author: String, From a9dc28418d1726407caafe7b7dc78e059957efeb Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 3 Oct 2022 17:33:51 -0400 Subject: [PATCH 025/172] lib: added ability to search in all supported languages also coninue workig on pl filters --- git-function-history-lib/src/languages/c.rs | 7 +++++ git-function-history-lib/src/languages/mod.rs | 13 +++++++++ .../src/languages/python.rs | 15 +++++++++- .../src/languages/rust.rs | 2 ++ git-function-history-lib/src/lib.rs | 29 +++++++++++++++++++ 5 files changed, 65 insertions(+), 1 deletion(-) diff --git a/git-function-history-lib/src/languages/c.rs b/git-function-history-lib/src/languages/c.rs index c0fde261..99198c94 100644 --- a/git-function-history-lib/src/languages/c.rs +++ b/git-function-history-lib/src/languages/c.rs @@ -62,3 +62,10 @@ pub(crate) fn find_function_in_commit( ) -> FunctionResult { todo!("find_function_in_commit") } + +pub enum Filter { + /// when you want filter by a function that has a parent function of a specific name + FunctionWithParent(String), + /// when you want to filter by a function that has a has a specific return type + FunctionWithReturnType(String), +} diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 26f45b97..ff7d9411 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -7,6 +7,17 @@ pub enum Language { Rust, /// c language C, + /// all available languages + All, +} + +pub enum LanguageFilter { + /// python filter + Python(python::Filter), + /// rust filter + Rust(rust::Filter), + /// c filter + C(c::Filter), } impl Language { @@ -15,6 +26,7 @@ impl Language { "python" => Ok(Self::Python), "rust" => Ok(Self::Rust), "c" => Ok(Self::C), + "all" => Ok(Self::All), _ => Err(format!("Unknown language: {}", s))?, } } @@ -26,6 +38,7 @@ impl fmt::Display for Language { Self::Python => write!(f, "python"), Self::Rust => write!(f, "rust"), Self::C => write!(f, "c"), + Self::All => write!(f, "all"), } } } diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index a78f2412..1b84aff3 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -16,7 +16,7 @@ pub struct Function { pub(crate) decorators: Vec, pub(crate) class: Option, pub(crate) lines: (usize, usize), - returns: Option, + pub(crate) returns: Option, } impl Function {} @@ -340,3 +340,16 @@ fn get_functions<'a>( } } } + +pub enum Filter { + /// when you want to filter by function that are in a specific class + FunctionInClass(String), + /// when you want filter by a function that has a parent function of a specific name + FunctionWithParent(String), + /// when you want to filter by a function that has a has a specific return type + FunctionWithReturnType(String), + /// when you want to filter by a function that has a specific parameter name + FunctionWithParameterName(String), + /// when you want to filter by a function that has a specific decorator + FunctionWithDecorator(String), +} diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index f8d00547..32bbe665 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -575,6 +575,8 @@ pub enum Filter { FunctionWithReturnType(String), /// when you want to filter by a function that has a specific parameter type FunctionWithParameterType(String), + /// when you want to filter by a function that has a specific parameter name + FunctionWithParameterName(String), /// when you want to filter by a function that has a specific lifetime FunctionWithLifetime(String), /// when you want to filter by a function that has a specific generic with name diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 4f6fa763..43e867df 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -200,6 +200,7 @@ pub fn get_function_history( Err("file is not a rust file")?; } } + Language::All => {} } } #[cfg(feature = "parallel")] @@ -322,6 +323,9 @@ fn find_function_in_commit_with_filetype( files.push(file); } } + Language::All => { + files.push(file); + } } } _ => {} @@ -374,6 +378,31 @@ fn find_function_in_commit( types::FileType::Python(functions), )) } + Language::All => match file_path.split('.').last() { + Some("rs") => { + let functions = rust::find_function_in_commit(commit, file_path, name)?; + Ok(File::new( + file_path.to_string(), + types::FileType::Rust(functions), + )) + } + Some("c") | Some("h") => { + let functions = languages::c::find_function_in_commit(commit, file_path, name)?; + Ok(File::new( + file_path.to_string(), + types::FileType::C(functions), + )) + } + Some("py") => { + let functions = + languages::python::find_function_in_commit(commit, file_path, name)?; + Ok(File::new( + file_path.to_string(), + types::FileType::Python(functions), + )) + } + _ => Err("unknown file type")?, + }, } } From a22e03fd0503c1e5e24712a9d948c69656eefc60 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Mon, 3 Oct 2022 21:34:30 +0000 Subject: [PATCH 026/172] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b98ada18..4f517257 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ All notable changes to this project will be documented in this file. - Moved away from using mostly enerics to using enums - Python works besides for one edge case when the function is the last node - Non proggraming languge (pl) filters addded back +- Added ability to search in all supported languages ### Tui From 8212ae6430800050db816e87568480c7c1738144 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 3 Oct 2022 23:48:01 -0400 Subject: [PATCH 027/172] lib: pl filters now working very messy and boilerplatety a lot of things need rethinking --- git-function-history-lib/src/languages/c.rs | 17 +- git-function-history-lib/src/languages/mod.rs | 2 +- .../src/languages/python.rs | 23 +- .../src/languages/rust.rs | 30 +- git-function-history-lib/src/lib.rs | 20 +- git-function-history-lib/src/types.rs | 386 +++++++++++++----- 6 files changed, 358 insertions(+), 120 deletions(-) diff --git a/git-function-history-lib/src/languages/c.rs b/git-function-history-lib/src/languages/c.rs index 99198c94..7c7b502f 100644 --- a/git-function-history-lib/src/languages/c.rs +++ b/git-function-history-lib/src/languages/c.rs @@ -62,10 +62,25 @@ pub(crate) fn find_function_in_commit( ) -> FunctionResult { todo!("find_function_in_commit") } - +#[derive(Debug, Clone, PartialEq, Eq)] pub enum Filter { /// when you want filter by a function that has a parent function of a specific name FunctionWithParent(String), /// when you want to filter by a function that has a has a specific return type FunctionWithReturnType(String), } + +impl Filter { + pub fn matches(&self, function: &Function) -> bool { + match self { + Self::FunctionWithParent(parent) => function + .parent + .iter() + .any(|parent_function| parent_function.name == *parent), + Self::FunctionWithReturnType(return_type) => function + .returns + .as_ref() + .map_or(false, |r| r == return_type), + } + } +} diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index ff7d9411..c6646365 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -10,7 +10,7 @@ pub enum Language { /// all available languages All, } - +#[derive(Debug, Clone, PartialEq, Eq)] pub enum LanguageFilter { /// python filter Python(python::Filter), diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 1b84aff3..7735e99d 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -340,7 +340,7 @@ fn get_functions<'a>( } } } - +#[derive(Debug, Clone, PartialEq, Eq)] pub enum Filter { /// when you want to filter by function that are in a specific class FunctionInClass(String), @@ -353,3 +353,24 @@ pub enum Filter { /// when you want to filter by a function that has a specific decorator FunctionWithDecorator(String), } + +impl Filter { + pub fn matches(&self, function: &Function) -> bool { + match self { + Self::FunctionInClass(class) => { + function.class.as_ref().map_or(false, |x| x.name == *class) + } + Self::FunctionWithParent(parent) => function.parent.iter().any(|x| x.name == *parent), + Self::FunctionWithReturnType(return_type) => function + .returns + .as_ref() + .map_or(false, |x| x == return_type), + Self::FunctionWithParameterName(parameter_name) => { + function.parameters.iter().any(|x| x == parameter_name) + } + Self::FunctionWithDecorator(decorator) => { + function.decorators.iter().any(|x| x == decorator) + } + } + } +} diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 32bbe665..a89bfe13 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -226,7 +226,7 @@ impl FunctionBlock { } /// This holds information about when a function is in an impl/trait/extern block -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Block { /// The name of the block ie for `impl` it would be the type were impling for pub(crate) name: Option, @@ -565,10 +565,10 @@ fn get_doc_comments_and_attrs(block: &T) -> (Vec, Vec .collect::>(), ) } - +#[derive(Debug, Clone, PartialEq, Eq)] pub enum Filter { /// when you want to filter by function that are in a specific block (impl, trait, extern) - FunctionInBlock(Block), + FunctionInBlock(BlockType), /// when you want filter by a function that has a parent function of a specific name FunctionWithParent(String), /// when you want to filter by a function that has a has a specific return type @@ -584,3 +584,27 @@ pub enum Filter { /// when you want to filter by a function that has a specific attribute FunctionWithAttribute(String), } + +impl Filter { + pub fn matches(&self, function: &Function) -> bool { + match self { + Self::FunctionInBlock(block_type) => function + .block + .as_ref() + .map_or(false, |block| block.block_type == *block_type), + Self::FunctionWithParent(parent) => function.function.iter().any(|f| f.name == *parent), + Self::FunctionWithReturnType(return_type) => { + function.return_type == Some(return_type.to_string()) + } + Self::FunctionWithParameterType(parameter_type) => { + function.arguments.values().any(|x| x == parameter_type) + } + Self::FunctionWithParameterName(parameter_name) => { + function.arguments.keys().any(|x| x == parameter_name) + } + Self::FunctionWithLifetime(lifetime) => function.lifetime.contains(lifetime), + Self::FunctionWithGeneric(generic) => function.generics.contains(generic), + Self::FunctionWithAttribute(attribute) => function.attributes.contains(attribute), + } + } +} diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 43e867df..924df067 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -18,7 +18,7 @@ pub mod languages; /// Different types that can extracted from the result of `get_function_history`. pub mod types; -use languages::rust; +use languages::{rust, LanguageFilter}; #[cfg(feature = "parallel")] use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; @@ -56,16 +56,16 @@ pub enum Filter { FileRelative(String), /// When you want to filter only files in a specific directory Directory(String), - /// when you want to filter by function that are in between specific lines FunctionInLines(usize, usize), - /// when you want to filter by a any commit author name that contains a specific string Author(String), /// when you want to filter by a any commit author email that contains a specific string AuthorEmail(String), // when you want to filter by a a commit message that contains a specific string Message(String), + /// when you want to filter by proggramming language filter + PLFilter(LanguageFilter), /// When you want to filter by nothing. None, } @@ -361,21 +361,21 @@ fn find_function_in_commit( let functions = rust::find_function_in_commit(commit, file_path, name)?; Ok(File::new( file_path.to_string(), - types::FileType::Rust(functions), + types::FileType::Rust(functions, 0), )) } Language::C => { let functions = languages::c::find_function_in_commit(commit, file_path, name)?; Ok(File::new( file_path.to_string(), - types::FileType::C(functions), + types::FileType::C(functions, 0), )) } Language::Python => { let functions = languages::python::find_function_in_commit(commit, file_path, name)?; Ok(File::new( file_path.to_string(), - types::FileType::Python(functions), + types::FileType::Python(functions, 0), )) } Language::All => match file_path.split('.').last() { @@ -383,14 +383,14 @@ fn find_function_in_commit( let functions = rust::find_function_in_commit(commit, file_path, name)?; Ok(File::new( file_path.to_string(), - types::FileType::Rust(functions), + types::FileType::Rust(functions, 0), )) } - Some("c") | Some("h") => { + Some("c" | "h") => { let functions = languages::c::find_function_in_commit(commit, file_path, name)?; Ok(File::new( file_path.to_string(), - types::FileType::C(functions), + types::FileType::C(functions, 0), )) } Some("py") => { @@ -398,7 +398,7 @@ fn find_function_in_commit( languages::python::find_function_in_commit(commit, file_path, name)?; Ok(File::new( file_path.to_string(), - types::FileType::Python(functions), + types::FileType::Python(functions, 0), )) } _ => Err("unknown file type")?, diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 35891d02..39fe75ff 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -1,10 +1,11 @@ use chrono::{DateTime, FixedOffset}; +use rayon::prelude::IntoParallelRefIterator; #[cfg(feature = "parallel")] use rayon::prelude::ParallelIterator; use std::{collections::HashMap, error::Error, fmt}; use crate::{ - languages::{c, python, rust, Function}, + languages::{c, python, rust, Function, LanguageFilter}, Filter, }; @@ -37,22 +38,113 @@ impl File { &mut self.functions } - // /// This is will get the current function in the file - // pub fn get_current_function(&self) -> Option<&FileType> { - // self.functions.get(self.current_pos) - // } + pub fn filter_by(&self, filter: &Filter) -> Result> { + match filter { + Filter::FunctionInLines(..) | Filter::PLFilter(_) => {} + Filter::None => return Ok(self.clone()), + _ => return Err("Filter not available")?, + } + let mut new_file = self.clone(); + new_file.functions = match &self.functions { + FileType::Rust(functions, _) => { + let mut vec = Vec::new(); + for function in functions { + match &filter { + Filter::FunctionInLines(start, end) => { + if function.lines.0 >= *start && function.lines.1 <= *end { + vec.push(function.clone()); + } + } + Filter::PLFilter(LanguageFilter::Rust(filter)) => { + if filter.matches(function) { + vec.push(function.clone()); + } + } + _ => return Err("Filter not available")?, + } + } + if vec.is_empty() { + return Err("No functions found for filter")?; + } + FileType::Rust(vec, 0) + } - // /// This is will get the current function in the file (mutable) - // pub fn get_current_function_mut(&mut self) -> Option<&mut FileType> { - // self.functions.get_mut(self.current_pos) - // } + FileType::Python(functions, _) => { + let mut vec = Vec::new(); + for function in functions { + match &filter { + Filter::FunctionInLines(start, end) => { + if function.lines.0 >= *start && function.lines.1 <= *end { + vec.push(function.clone()); + } + } + Filter::PLFilter(LanguageFilter::Python(filter)) => { + if filter.matches(function) { + vec.push(function.clone()); + } + } + _ => return Err("Filter not available")?, + } + } + if vec.is_empty() { + return Err("No functions found for filter")?; + } + FileType::Python(vec, 0) + } + FileType::C(functions, _) => { + let mut vec = Vec::new(); + for function in functions { + match &filter { + Filter::FunctionInLines(start, end) => { + if function.lines.0 >= *start && function.lines.1 <= *end { + vec.push(function.clone()); + } + } + Filter::PLFilter(LanguageFilter::C(filter)) => { + if filter.matches(function) { + vec.push(function.clone()); + } + } + _ => return Err("Filter not available")?, + } + } + if vec.is_empty() { + return Err("No functions found for filter")?; + } + FileType::C(vec, 0) + } + }; + match &new_file.functions { + FileType::C(functions, _) => { + if functions.is_empty() { + return Err("No functions found for filter")?; + } + } + FileType::Python(functions, _) => { + if functions.is_empty() { + return Err("No functions found for filter")?; + } + } + FileType::Rust(functions, _) => { + if functions.is_empty() { + return Err("No functions found for filter")?; + } + } + } + Ok(new_file) + } + + /// This is will get the current function in the file + pub fn get_current_function(&self) -> Option { + self.functions.get(self.current_pos) + } } impl fmt::Display for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // write!(f, "{}", self.name) match &self.functions { - FileType::Python(python) => { + FileType::Python(python, _) => { for (i, function) in python.iter().enumerate() { write!( f, @@ -70,7 +162,7 @@ impl fmt::Display for File { function.fmt_with_context(f, previous, next)?; } } - FileType::Rust(rust) => { + FileType::Rust(rust, _) => { for (i, function) in rust.iter().enumerate() { write!( f, @@ -88,7 +180,7 @@ impl fmt::Display for File { function.fmt_with_context(f, previous, next)?; } } - FileType::C(c) => { + FileType::C(c, _) => { for (i, function) in c.iter().enumerate() { write!( f, @@ -110,14 +202,104 @@ impl fmt::Display for File { Ok(()) } } + +pub enum FunctionType { + Python(python::Function), + Rust(rust::Function), + C(c::Function), +} + +impl FunctionType { + pub const fn get_lines(&self) -> (usize, usize) { + match self { + Self::Python(python) => python.lines, + Self::Rust(rust) => rust.lines, + Self::C(c) => c.lines, + } + } +} + +impl Iterator for File { + type Item = FunctionType; + + fn next(&mut self) -> Option { + let current = self.current_pos; + self.current_pos += 1; + + match &self.functions { + FileType::Python(python, _) => { + python.get(current).map(|f| FunctionType::Python(f.clone())) + } + FileType::Rust(rust, _) => rust.get(current).map(|f| FunctionType::Rust(f.clone())), + FileType::C(c, _) => c.get(current).map(|f| FunctionType::C(f.clone())), + } + } +} + #[derive(Debug, Clone)] pub enum FileType { /// The python language - Python(Vec), + Python(Vec, usize), /// The rust language - Rust(Vec), + Rust(Vec, usize), /// c language - C(Vec), + C(Vec, usize), +} + +impl Iterator for FileType { + type Item = FunctionType; + + fn next(&mut self) -> Option { + match self { + Self::Python(python, pos) => python.get(*pos).map(|f| { + *pos += 1; + FunctionType::Python(f.clone()) + }), + Self::Rust(rust, pos) => rust.get(*pos).map(|f| { + *pos += 1; + FunctionType::Rust(f.clone()) + }), + + Self::C(c, pos) => c.get(*pos).map(|f| { + *pos += 1; + FunctionType::C(f.clone()) + }), + } + } +} + +impl FileType { + pub fn get(&self, index: usize) -> Option { + match self { + Self::Rust(rust, _) => rust + .get(index) + .map(|function| FunctionType::Rust(function.clone())), + Self::C(c, _) => c + .get(index) + .map(|function| FunctionType::C(function.clone())), + Self::Python(python, _) => python + .get(index) + .map(|function| FunctionType::Python(function.clone())), + } + } + + pub fn get_current< + T: Clone + From + From + From, + >( + &self, + ) -> Vec { + match self { + Self::Python(python, _pos) => python + .iter() + .map(|function| T::from(function.clone())) + .collect(), + Self::Rust(rust, _pos) => rust + .iter() + .map(|function| T::from(function.clone())) + .collect(), + Self::C(c, _pos) => c.iter().map(|function| T::from(function.clone())).collect(), + } + } } /// This holds information like date and commit `commit_hash` and also the list of function found in the commit. @@ -206,51 +388,48 @@ impl CommitFunctions { /// returns a new `CommitFunctions` by filtering the current one by the filter specified (does not modify the current one). /// - /// valid filters are: `Filter::FunctionInBlock`, `Filter::FunctionInLines`, `Filter::FunctionWithParent`, and `Filter::FileAbsolute`, `Filter::FileRelative`, and `Filter::Directory`. - pub fn filter_by(&self, _filter: &Filter) -> Result> { - // let mut vec = Vec::new(); - // for f in &self.files { - // match filter { - // Filter::FileAbsolute(file) => { - // if f.name == *file { - // vec.push(f.clone()); - // } - // } - // Filter::FileRelative(file) => { - // if f.name.ends_with(file) { - // vec.push(f.clone()); - // } - // } - // Filter::Directory(dir) => { - // if f.name.contains(dir) { - // vec.push(f.clone()); - // } - // } - // Filter::FunctionInLines(..) - // | Filter::FunctionWithParent(_) - // | Filter::FunctionInBlock(_) => { - // if f.filter_by(filter).is_ok() { - // vec.push(f.clone()); - // } - // } - // Filter::None => vec.push(f.clone()), - // _ => Err("Invalid filter")?, - // } - // } - // if vec.is_empty() { - // return Err("No files found for filter")?; - // } - // Ok(Self { - // commit_hash: self.commit_hash.clone(), - // files: vec, - // date: self.date, - // current_pos: 0, - // current_iter_pos: 0, - // author: self.author.clone(), - // email: self.email.clone(), - // message: self.message.clone(), - // }) - todo!() + /// valid filters are: `Filter::FunctionInLines`, and `Filter::FileAbsolute`, `Filter::FileRelative`, and `Filter::Directory`. + pub fn filter_by(&self, filter: &Filter) -> Result> { + match filter { + Filter::FileAbsolute(_) + | Filter::FileRelative(_) + | Filter::Directory(_) + | Filter::FunctionInLines(..) + | Filter::PLFilter(_) => {} + Filter::None => { + return Ok(self.clone()); + } + _ => Err("Invalid filter")?, + } + #[cfg(feature = "parallel")] + let t = self.files.iter(); + #[cfg(not(feature = "parallel"))] + let t = self.files.iter(); + let vec: Vec<_> = t + .filter(|f| match filter { + Filter::FileAbsolute(file) => f.name == *file, + Filter::FileRelative(file) => f.name.ends_with(file), + Filter::Directory(dir) => f.name.contains(dir), + Filter::FunctionInLines(..) | Filter::PLFilter(_) => f.filter_by(filter).is_ok(), + Filter::None => true, + _ => false, + }) + .cloned() + .collect(); + + if vec.is_empty() { + return Err("No files found for filter")?; + } + Ok(Self { + commit_hash: self.commit_hash.clone(), + files: vec, + date: self.date, + current_pos: 0, + current_iter_pos: 0, + author: self.author.clone(), + email: self.email.clone(), + message: self.message.clone(), + }) } } @@ -371,50 +550,49 @@ impl FunctionHistory { /// /// history.filter_by(Filter::Directory("app".to_string())).unwrap(); /// ``` - pub fn filter_by(&self, _filter: &Filter) -> Result> { - // #[cfg(feature = "parallel")] - // let t = self.commit_history.par_iter(); - // #[cfg(not(feature = "parallel"))] - // let t = self.commit_history.iter(); - // let vec: Vec = t - // .filter(|f| match filter { - // Filter::FunctionInLines(..) - // | Filter::FunctionWithParent(_) - // | Filter::FunctionInBlock(_) - // | Filter::Directory(_) - // | Filter::FileAbsolute(_) - // | Filter::FileRelative(_) => f.filter_by(filter).is_ok(), - // Filter::CommitHash(commit_hash) => &f.commit_hash == commit_hash, - // Filter::Date(date) => &f.date.to_rfc2822() == date, - // Filter::DateRange(start, end) => { - // let start = match DateTime::parse_from_rfc2822(start) { - // Ok(date) => date, - // Err(_) => return false, - // }; - // let end = match DateTime::parse_from_rfc2822(end) { - // Ok(date) => date, - // Err(_) => return false, - // }; - // f.date >= start || f.date <= end - // } - // Filter::Author(author) => &f.author == author, - // Filter::AuthorEmail(email) => &f.email == email, - // Filter::Message(message) => f.message.contains(message), - // Filter::None => true, - // }) - // .cloned() - // .collect(); - - // if vec.is_empty() { - // return Err("No history found for the filter")?; - // } - // Ok(Self { - // commit_history: vec, - // name: self.name.clone(), - // current_pos: 0, - // current_iter_pos: 0, - // }) - todo!() + pub fn filter_by(&self, filter: &Filter) -> Result> { + #[cfg(feature = "parallel")] + let t = self.commit_history.par_iter(); + #[cfg(not(feature = "parallel"))] + let t = self.commit_history.iter(); + let vec: Vec = t + .filter(|f| match filter { + Filter::FunctionInLines(..) + | Filter::Directory(_) + | Filter::FileAbsolute(_) + | Filter::PLFilter(_) + | Filter::FileRelative(_) => f.filter_by(filter).is_ok(), + Filter::CommitHash(commit_hash) => &f.commit_hash == commit_hash, + Filter::Date(date) => &f.date.to_rfc2822() == date, + Filter::DateRange(start, end) => { + let start = match DateTime::parse_from_rfc2822(start) { + Ok(date) => date, + Err(_) => return false, + }; + let end = match DateTime::parse_from_rfc2822(end) { + Ok(date) => date, + Err(_) => return false, + }; + f.date >= start || f.date <= end + } + + Filter::Author(author) => &f.author == author, + Filter::AuthorEmail(email) => &f.email == email, + Filter::Message(message) => f.message.contains(message), + Filter::None => true, + }) + .cloned() + .collect(); + + if vec.is_empty() { + return Err("No history found for the filter")?; + } + Ok(Self { + commit_history: vec, + name: self.name.clone(), + current_pos: 0, + current_iter_pos: 0, + }) } } From 254eb78ad31b5b00e630344b0a4bb5fce3851595 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Tue, 4 Oct 2022 03:48:38 +0000 Subject: [PATCH 028/172] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f517257..6fa0797b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ All notable changes to this project will be documented in this file. - Python works besides for one edge case when the function is the last node - Non proggraming languge (pl) filters addded back - Added ability to search in all supported languages +- Pl filters now working very messy and boilerplatety ### Tui From 8bb603b968dcbb0dae13379521b22cb3e609fb16 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Tue, 4 Oct 2022 09:26:57 -0400 Subject: [PATCH 029/172] working on c parsing --- git-function-history-lib/src/test_functions.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 git-function-history-lib/src/test_functions.c diff --git a/git-function-history-lib/src/test_functions.c b/git-function-history-lib/src/test_functions.c new file mode 100644 index 00000000..3eab266e --- /dev/null +++ b/git-function-history-lib/src/test_functions.c @@ -0,0 +1,19 @@ +#include + +void test_function(void); + +void test_function2(void) +{ + printf("Hello World!" ); +} + +int main() +{ + printf("Hello World!"); + return 0; +} + +void test_function(void) +{ + printf("Hello World!"); +} \ No newline at end of file From 15f2c36c3563d89ada6e688c33038fcc010efc38 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 6 Oct 2022 01:19:29 -0400 Subject: [PATCH 030/172] realized c-lang support is comlicated, it will be an optinal feature --- TODO.md | 2 +- git-function-history-gui/src/lib.rs | 5 +- git-function-history-lib/Cargo.toml | 1 + git-function-history-lib/README.md | 1 + git-function-history-lib/src/languages/c.rs | 12 ++-- git-function-history-lib/src/languages/mod.rs | 6 +- git-function-history-lib/src/lib.rs | 50 ++++++++++++-- git-function-history-lib/src/types.rs | 65 ++++++++++++++----- 8 files changed, 110 insertions(+), 32 deletions(-) diff --git a/TODO.md b/TODO.md index 54b80bb7..00ce4558 100644 --- a/TODO.md +++ b/TODO.md @@ -10,7 +10,7 @@ - GUI - [x] fix `thread '' panicked at 'channel disconnected', function_history_backend_thread/src/lib.rs:33:25` error (handling when the channel is disconnected at the end of the program) - - [x] add new documentation for the new filters and fix some old documentation that talks about filter commitfunctions and files etc + - [x] add new documentation for the new filters and fix some old documentation that talks about filter and files etc - TUI - [x] use a proper input box for the edit bar, so that delete and scrolling the input works - [x] finish documentation diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index e889dd59..ac63030c 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -15,8 +15,7 @@ use function_history_backend_thread::types::{ use git_function_history::{ languages::Language, types::Directions, - // BlockType, - CommitFunctions, + Commit, FileType, Filter, FunctionHistory, @@ -61,7 +60,7 @@ impl MyEguiApp { } } - fn draw_commit(commit: &mut CommitFunctions, ctx: &egui::Context, show: bool) { + fn draw_commit(commit: &mut Commit, ctx: &egui::Context, show: bool) { if show { TopBottomPanel::top("date_id").show(ctx, |ui| { ui.add(Label::new(format!( diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 65ac1748..7e7ff207 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -11,6 +11,7 @@ description = "show function history from git" [features] default = ["parallel"] parallel = ["dep:rayon"] +c-lang = [] [dependencies] chrono = "0.4.22" diff --git a/git-function-history-lib/README.md b/git-function-history-lib/README.md index 8526302a..b7273272 100644 --- a/git-function-history-lib/README.md +++ b/git-function-history-lib/README.md @@ -11,3 +11,4 @@ Use the latest [crates.io](https://crates.io/crates/git_function_history) by put - parallel: use rayon to parallelize the git log search - --no-default-features: disable parallelism +- c-lang: adds support c (requires you to have a c compiler installed) (see the [c-lib]() docs for more information) \ No newline at end of file diff --git a/git-function-history-lib/src/languages/c.rs b/git-function-history-lib/src/languages/c.rs index 7c7b502f..f4dea8f1 100644 --- a/git-function-history-lib/src/languages/c.rs +++ b/git-function-history-lib/src/languages/c.rs @@ -1,4 +1,5 @@ -use std::collections::HashMap; +use std::{collections::HashMap}; + use super::FunctionResult; #[derive(Debug, Clone)] @@ -56,10 +57,13 @@ pub struct ParentFunction { } pub(crate) fn find_function_in_commit( - _commit: &str, - _file_path: &str, - _name: &str, + commit: &str, + file_path: &str, + name: &str, ) -> FunctionResult { + println!("Finding function {} in commit {}", name, commit); + let file_contents = crate::find_file_in_commit(commit, file_path)?; + todo!("find_function_in_commit") } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index c6646365..5debc2f9 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -5,6 +5,7 @@ pub enum Language { Python, /// The rust language Rust, + #[cfg(feature = "c-lang")] /// c language C, /// all available languages @@ -16,6 +17,7 @@ pub enum LanguageFilter { Python(python::Filter), /// rust filter Rust(rust::Filter), + #[cfg(feature = "c-lang")] /// c filter C(c::Filter), } @@ -25,6 +27,7 @@ impl Language { match s { "python" => Ok(Self::Python), "rust" => Ok(Self::Rust), + #[cfg(feature = "c-lang")] "c" => Ok(Self::C), "all" => Ok(Self::All), _ => Err(format!("Unknown language: {}", s))?, @@ -37,12 +40,13 @@ impl fmt::Display for Language { match self { Self::Python => write!(f, "python"), Self::Rust => write!(f, "rust"), + #[cfg(feature = "c-lang")] Self::C => write!(f, "c"), Self::All => write!(f, "all"), } } } - +#[cfg(feature = "c-lang")] pub mod c; pub mod python; pub mod rust; diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 924df067..e4784b1c 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -23,7 +23,7 @@ use languages::{rust, LanguageFilter}; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use std::{error::Error, process::Command}; -pub use types::{CommitFunctions, File, FunctionHistory}; +pub use types::{Commit, File, FunctionHistory}; use crate::languages::Language; @@ -185,22 +185,31 @@ pub fn get_function_history( // check if file is a rust file if let FileType::Absolute(path) | FileType::Relative(path) = &file { match langs { + #[cfg(feature = "c-lang")] Language::C => { if !path.ends_with(".c") || !path.ends_with(".h") { - Err("file is not a c file")?; + Err(format!("file is not a c file: {}", path))?; } } Language::Python => { if !path.ends_with(".py") { - Err("file is not a python file")?; + Err(format!("file is not a python file: {}", path))?; } } Language::Rust => { if !path.ends_with(".rs") { - Err("file is not a rust file")?; + Err(format!("file is not a rust file: {}", path))?; + } + } + Language::All => { + if !path.ends_with(".rs") + || !path.ends_with(".py") + || !path.ends_with(".c") + || !path.ends_with(".h") + { + Err(format!("file is supported: {}", path))?; } } - Language::All => {} } } #[cfg(feature = "parallel")] @@ -211,7 +220,7 @@ pub fn get_function_history( .filter_map(|commit| match &file { FileType::Absolute(path) => { match find_function_in_commit(commit.0, path, name, *langs) { - Ok(contents) => Some(CommitFunctions::new( + Ok(contents) => Some(Commit::new( commit.0.to_string(), vec![contents], commit.1, @@ -225,7 +234,7 @@ pub fn get_function_history( FileType::Relative(_) | FileType::None | FileType::Directory(_) => { match find_function_in_commit_with_filetype(commit.0, name, file, *langs) { - Ok(contents) => Some(CommitFunctions::new( + Ok(contents) => Some(Commit::new( commit.0.to_string(), contents, commit.1, @@ -307,6 +316,7 @@ fn find_function_in_commit_with_filetype( } FileType::None => { match langs { + #[cfg(feature = "c-lang")] Language::C => { if file.ends_with(".c") || file.ends_with(".h") { files.push(file); @@ -364,6 +374,7 @@ fn find_function_in_commit( types::FileType::Rust(functions, 0), )) } + #[cfg(feature = "c-lang")] Language::C => { let functions = languages::c::find_function_in_commit(commit, file_path, name)?; Ok(File::new( @@ -386,6 +397,7 @@ fn find_function_in_commit( types::FileType::Rust(functions, 0), )) } + #[cfg(feature = "c-lang")] Some("c" | "h") => { let functions = languages::c::find_function_in_commit(commit, file_path, name)?; Ok(File::new( @@ -548,4 +560,28 @@ mod tests { } assert!(output.is_ok()); } + + #[test] + #[cfg(feature = "c-lang")] + fn c_lang() { + let now = Utc::now(); + let output = get_function_history( + "empty_test", + &FileType::Relative("src/test_functions.c".to_string()), + &Filter::DateRange( + "03 Oct 2022 11:27:23 -0400".to_owned(), + "05 Oct 2022 23:45:52 +0000".to_owned(), + ), + &languages::Language::C, + ); + let after = Utc::now() - now; + println!("time taken: {}", after.num_seconds()); + match &output { + Ok(functions) => { + println!("{}", functions); + } + Err(e) => println!("{}", e), + } + assert!(output.is_ok()); + } } diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 39fe75ff..ebcf8b57 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -5,10 +5,13 @@ use rayon::prelude::ParallelIterator; use std::{collections::HashMap, error::Error, fmt}; use crate::{ - languages::{c, python, rust, Function, LanguageFilter}, + languages::{python, rust, Function, LanguageFilter}, Filter, }; +#[cfg(feature = "c-lang")] +use crate::languages::c; + /// This is used to store each individual file in a commit and the associated functions in that file. #[derive(Debug, Clone)] pub struct File { @@ -91,6 +94,7 @@ impl File { } FileType::Python(vec, 0) } + #[cfg(feature = "c-lang")] FileType::C(functions, _) => { let mut vec = Vec::new(); for function in functions { @@ -115,6 +119,7 @@ impl File { } }; match &new_file.functions { + #[cfg(feature = "c-lang")] FileType::C(functions, _) => { if functions.is_empty() { return Err("No functions found for filter")?; @@ -180,6 +185,7 @@ impl fmt::Display for File { function.fmt_with_context(f, previous, next)?; } } + #[cfg(feature = "c-lang")] FileType::C(c, _) => { for (i, function) in c.iter().enumerate() { write!( @@ -206,6 +212,7 @@ impl fmt::Display for File { pub enum FunctionType { Python(python::Function), Rust(rust::Function), + #[cfg(feature = "c-lang")] C(c::Function), } @@ -214,6 +221,7 @@ impl FunctionType { match self { Self::Python(python) => python.lines, Self::Rust(rust) => rust.lines, + #[cfg(feature = "c-lang")] Self::C(c) => c.lines, } } @@ -231,6 +239,7 @@ impl Iterator for File { python.get(current).map(|f| FunctionType::Python(f.clone())) } FileType::Rust(rust, _) => rust.get(current).map(|f| FunctionType::Rust(f.clone())), + #[cfg(feature = "c-lang")] FileType::C(c, _) => c.get(current).map(|f| FunctionType::C(f.clone())), } } @@ -242,6 +251,7 @@ pub enum FileType { Python(Vec, usize), /// The rust language Rust(Vec, usize), + #[cfg(feature = "c-lang")] /// c language C(Vec, usize), } @@ -259,7 +269,7 @@ impl Iterator for FileType { *pos += 1; FunctionType::Rust(f.clone()) }), - + #[cfg(feature = "c-lang")] Self::C(c, pos) => c.get(*pos).map(|f| { *pos += 1; FunctionType::C(f.clone()) @@ -274,6 +284,7 @@ impl FileType { Self::Rust(rust, _) => rust .get(index) .map(|function| FunctionType::Rust(function.clone())), + #[cfg(feature = "c-lang")] Self::C(c, _) => c .get(index) .map(|function| FunctionType::C(function.clone())), @@ -282,9 +293,12 @@ impl FileType { .map(|function| FunctionType::Python(function.clone())), } } - + #[cfg(feature = "c-lang")] pub fn get_current< - T: Clone + From + From + From, + T: Clone + From + + + From + + From, >( &self, ) -> Vec { @@ -300,11 +314,30 @@ impl FileType { Self::C(c, _pos) => c.iter().map(|function| T::from(function.clone())).collect(), } } + + #[cfg(not(feature = "c-lang"))] + pub fn get_current< + T: Clone + From + From, + >( + &self, + ) -> Vec { + match self { + Self::Python(python, _pos) => python + .iter() + .map(|function| T::from(function.clone())) + .collect(), + Self::Rust(rust, _pos) => rust + .iter() + .map(|function| T::from(function.clone())) + .collect(), + } + } + } /// This holds information like date and commit `commit_hash` and also the list of function found in the commit. #[derive(Debug, Clone)] -pub struct CommitFunctions { +pub struct Commit { commit_hash: String, files: Vec, pub(crate) date: DateTime, @@ -315,8 +348,8 @@ pub struct CommitFunctions { message: String, } -impl CommitFunctions { - /// Create a new `CommitFunctions` with the given `commit_hash`, functions, and date. +impl Commit { + /// Create a new `Commit` with the given `commit_hash`, functions, and date. pub fn new( commit_hash: String, files: Vec, @@ -386,7 +419,7 @@ impl CommitFunctions { } } - /// returns a new `CommitFunctions` by filtering the current one by the filter specified (does not modify the current one). + /// returns a new `Commit` by filtering the current one by the filter specified (does not modify the current one). /// /// valid filters are: `Filter::FunctionInLines`, and `Filter::FileAbsolute`, `Filter::FileRelative`, and `Filter::Directory`. pub fn filter_by(&self, filter: &Filter) -> Result> { @@ -433,7 +466,7 @@ impl CommitFunctions { } } -impl Iterator for CommitFunctions { +impl Iterator for Commit { type Item = File; fn next(&mut self) -> Option { // get the current function without removing it @@ -443,7 +476,7 @@ impl Iterator for CommitFunctions { } } -impl fmt::Display for CommitFunctions { +impl fmt::Display for Commit { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "{}", self.files[self.current_pos])?; Ok(()) @@ -454,7 +487,7 @@ impl fmt::Display for CommitFunctions { #[derive(Debug, Clone)] pub struct FunctionHistory { pub(crate) name: String, - pub(crate) commit_history: Vec, + pub(crate) commit_history: Vec, current_iter_pos: usize, current_pos: usize, @@ -462,7 +495,7 @@ pub struct FunctionHistory { impl FunctionHistory { // creates a new `FunctionHistory` from a list of commits - pub fn new(name: String, commit_history: Vec) -> Self { + pub fn new(name: String, commit_history: Vec) -> Self { Self { name, commit_history, @@ -515,12 +548,12 @@ impl FunctionHistory { } /// returns a mutable reference to the current commit - pub fn get_mut_commit(&mut self) -> &mut CommitFunctions { + pub fn get_mut_commit(&mut self) -> &mut Commit { &mut self.commit_history[self.current_pos] } /// returns a reference to the current commit - pub fn get_commit(&self) -> &CommitFunctions { + pub fn get_commit(&self) -> &Commit { &self.commit_history[self.current_pos] } @@ -555,7 +588,7 @@ impl FunctionHistory { let t = self.commit_history.par_iter(); #[cfg(not(feature = "parallel"))] let t = self.commit_history.iter(); - let vec: Vec = t + let vec: Vec = t .filter(|f| match filter { Filter::FunctionInLines(..) | Filter::Directory(_) @@ -604,7 +637,7 @@ impl fmt::Display for FunctionHistory { } impl Iterator for FunctionHistory { - type Item = CommitFunctions; + type Item = Commit; fn next(&mut self) -> Option { self.commit_history .get(self.current_iter_pos) From 099044c1ba15a29b19c7c33e58b8213383d43291 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 6 Oct 2022 17:14:06 -0400 Subject: [PATCH 031/172] shortened some code in lib --- git-function-history-gui/src/lib.rs | 7 +--- git-function-history-lib/src/languages/c.rs | 5 +-- git-function-history-lib/src/lib.rs | 44 +++++++++------------ git-function-history-lib/src/types.rs | 12 +----- 4 files changed, 24 insertions(+), 44 deletions(-) diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index ac63030c..8bd9ab13 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -13,12 +13,7 @@ use function_history_backend_thread::types::{ Command, CommandResult, FilterType, FullCommand, HistoryFilterType, ListType, Status, }; use git_function_history::{ - languages::Language, - types::Directions, - Commit, - FileType, - Filter, - FunctionHistory, + languages::Language, types::Directions, Commit, FileType, Filter, FunctionHistory, }; // TODO: stop cloning everyting and use references instead diff --git a/git-function-history-lib/src/languages/c.rs b/git-function-history-lib/src/languages/c.rs index f4dea8f1..67a3344d 100644 --- a/git-function-history-lib/src/languages/c.rs +++ b/git-function-history-lib/src/languages/c.rs @@ -1,5 +1,4 @@ -use std::{collections::HashMap}; - +use std::collections::HashMap; use super::FunctionResult; #[derive(Debug, Clone)] @@ -63,7 +62,7 @@ pub(crate) fn find_function_in_commit( ) -> FunctionResult { println!("Finding function {} in commit {}", name, commit); let file_contents = crate::find_file_in_commit(commit, file_path)?; - + todo!("find_function_in_commit") } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index e4784b1c..a067ed91 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -218,21 +218,10 @@ pub fn get_function_history( let t = commits.iter(); file_history.commit_history = t .filter_map(|commit| match &file { - FileType::Absolute(path) => { - match find_function_in_commit(commit.0, path, name, *langs) { - Ok(contents) => Some(Commit::new( - commit.0.to_string(), - vec![contents], - commit.1, - commit.2.to_string(), - commit.3.to_string(), - commit.4.to_string(), - )), - Err(_) => None, - } - } - - FileType::Relative(_) | FileType::None | FileType::Directory(_) => { + FileType::Absolute(_) + | FileType::Relative(_) + | FileType::None + | FileType::Directory(_) => { match find_function_in_commit_with_filetype(commit.0, name, file, *langs) { Ok(contents) => Some(Commit::new( commit.0.to_string(), @@ -309,6 +298,11 @@ fn find_function_in_commit_with_filetype( files.push(file); } } + FileType::Absolute(ref path) => { + if file == path { + files.push(file); + } + } FileType::Directory(ref path) => { if path.contains(path) { files.push(file); @@ -334,11 +328,16 @@ fn find_function_in_commit_with_filetype( } } Language::All => { - files.push(file); + if file.ends_with(".rs") + || file.ends_with(".py") + || file.ends_with(".c") + || file.ends_with(".h") + { + files.push(file); + } } } } - _ => {} } } let err = "no function found".to_string(); @@ -347,12 +346,7 @@ fn find_function_in_commit_with_filetype( #[cfg(not(feature = "parellel"))] let t = files.iter(); let returns: Vec = t - .filter_map( - |file| match find_function_in_commit(commit, file, name, langs) { - Ok(functions) => Some(functions), - Err(_) => None, - }, - ) + .filter_map(|file| find_function_in_commit(commit, file, name, langs).ok()) .collect(); if returns.is_empty() { Err(err)?; @@ -418,11 +412,11 @@ fn find_function_in_commit( } } -trait UwrapToError { +trait UnwrapToError { fn unwrap_to_error(self, message: &str) -> Result>; } -impl UwrapToError for Option { +impl UnwrapToError for Option { fn unwrap_to_error(self, message: &str) -> Result> { match self { Some(val) => Ok(val), diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index ebcf8b57..b3ecace1 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -295,10 +295,7 @@ impl FileType { } #[cfg(feature = "c-lang")] pub fn get_current< - T: Clone + From + - - From + - From, + T: Clone + From + From + From, >( &self, ) -> Vec { @@ -316,11 +313,7 @@ impl FileType { } #[cfg(not(feature = "c-lang"))] - pub fn get_current< - T: Clone + From + From, - >( - &self, - ) -> Vec { + pub fn get_current + From>(&self) -> Vec { match self { Self::Python(python, _pos) => python .iter() @@ -332,7 +325,6 @@ impl FileType { .collect(), } } - } /// This holds information like date and commit `commit_hash` and also the list of function found in the commit. From 94d004960e0815f30a8a76c04887aca095fc8d01 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Fri, 7 Oct 2022 01:18:24 -0400 Subject: [PATCH 032/172] partialy not working b/c enum_dispatch can't figure it out --- git-function-history-lib/Cargo.toml | 3 +- git-function-history-lib/src/languages/c.rs | 23 +- git-function-history-lib/src/languages/mod.rs | 20 +- .../src/languages/python.rs | 58 ++++- .../src/languages/rust.rs | 39 ++- git-function-history-lib/src/lib.rs | 10 +- git-function-history-lib/src/types.rs | 222 +++++++++++++++--- 7 files changed, 301 insertions(+), 74 deletions(-) diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 7e7ff207..c2a97db1 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -17,4 +17,5 @@ c-lang = [] chrono = "0.4.22" ra_ap_syntax = "0.0.131" rayon = { version = "1.5.1", optional = true } -rustpython-parser = "0.1.2" \ No newline at end of file +rustpython-parser = "0.1.2" +enum_dispatch = "0.3.8" \ No newline at end of file diff --git a/git-function-history-lib/src/languages/c.rs b/git-function-history-lib/src/languages/c.rs index 67a3344d..2a86bba5 100644 --- a/git-function-history-lib/src/languages/c.rs +++ b/git-function-history-lib/src/languages/c.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use super::FunctionResult; #[derive(Debug, Clone)] -pub struct Function { +pub struct CFunction { pub(crate) name: String, pub(crate) body: String, pub(crate) parameters: Vec, @@ -31,12 +31,12 @@ impl Function { } } -impl super::Function for Function { +impl super::Function for CFunction { fn fmt_with_context( &self, - _f: &mut std::fmt::Formatter<'_>, - _previous: Option<&Self>, - _next: Option<&Self>, + f: &mut std::fmt::Formatter<'_>, + previous: Box>, + next: Box>, ) -> std::fmt::Result { todo!() } @@ -44,6 +44,17 @@ impl super::Function for Function { fn get_metadata(&self) -> HashMap<&str, String> { todo!() } + fn get_lines(&self) -> (usize, usize) { + self.lines + } + + fn matches(&self, filter: &LanguageFilter) -> bool { + if let LanguageFilter::C(filt) = filter { + filt.matches(self) + } else { + false + } + } } #[derive(Debug, Clone)] pub struct ParentFunction { @@ -74,7 +85,7 @@ pub enum Filter { } impl Filter { - pub fn matches(&self, function: &Function) -> bool { + pub fn matches(&self, function: &CFunction) -> bool { match self { Self::FunctionWithParent(parent) => function .parent diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 5debc2f9..13fd0361 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -5,7 +5,7 @@ pub enum Language { Python, /// The rust language Rust, - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] /// c language C, /// all available languages @@ -17,7 +17,7 @@ pub enum LanguageFilter { Python(python::Filter), /// rust filter Rust(rust::Filter), - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] /// c filter C(c::Filter), } @@ -27,7 +27,7 @@ impl Language { match s { "python" => Ok(Self::Python), "rust" => Ok(Self::Rust), - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] "c" => Ok(Self::C), "all" => Ok(Self::All), _ => Err(format!("Unknown language: {}", s))?, @@ -40,25 +40,29 @@ impl fmt::Display for Language { match self { Self::Python => write!(f, "python"), Self::Rust => write!(f, "rust"), - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] Self::C => write!(f, "c"), Self::All => write!(f, "all"), } } } -#[cfg(feature = "c-lang")] +#[cfg(feature = "c_lang")] pub mod c; pub mod python; pub mod rust; -pub trait Function { +pub trait Function: fmt::Debug + Clone + fmt::Display { fn fmt_with_context( &self, f: &mut fmt::Formatter<'_>, - previous: Option<&Self>, - next: Option<&Self>, + previous: Box>, + next: Box>, ) -> fmt::Result; fn get_metadata(&self) -> HashMap<&str, String>; + + fn get_lines(&self) -> (usize, usize); + + fn matches(&self, filter: &LanguageFilter) -> bool; } pub type FunctionResult = Result, Box>; diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 7735e99d..a66367e5 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::{collections::HashMap, fmt}; use rustpython_parser::{ ast::{Located, StatementType}, @@ -6,8 +6,10 @@ use rustpython_parser::{ parser, }; +use super::LanguageFilter; + #[derive(Debug, Clone)] -pub struct Function { +pub struct PythonFunction { pub(crate) name: String, pub(crate) body: String, // parameters: Params, @@ -19,17 +21,39 @@ pub struct Function { pub(crate) returns: Option, } -impl Function {} +impl fmt::Display for PythonFunction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.class { + Some(ref class) => write!(f, "{}", class.top)?, + None => {} + } + for parent in &self.parent { + write!(f, "{}", parent.top)?; + } + write!(f, "{}", self.body)?; + for parent in &self.parent { + write!(f, "{}", parent.bottom)?; + } + match self.class { + Some(ref class) => write!(f, "{}", class.bottom), + None => Ok(()), + } + } +} +impl PythonFunction {} -impl super::Function for Function { +impl super::Function for PythonFunction { + fn get_lines(&self) -> (usize, usize) { + self.lines + } fn fmt_with_context( &self, f: &mut std::fmt::Formatter<'_>, - previous: Option<&Self>, - next: Option<&Self>, + previous: Box>, + next: Box>, ) -> std::fmt::Result { match &self.class { - Some(class) => match previous { + Some(class) => match previous.as_ref() { Some(previous) => { if previous.class.is_some() { if previous.class.as_ref().unwrap().name == class.name { @@ -48,7 +72,7 @@ impl super::Function for Function { None => {} }; if !self.parent.is_empty() { - match previous { + match previous.as_ref() { None => { for parent in &self.parent { writeln!(f, "{}", parent.top)?; @@ -66,7 +90,7 @@ impl super::Function for Function { } write!(f, "{}", self.body)?; if !self.parent.is_empty() { - match next { + match next.as_ref() { None => { for parent in &self.parent { writeln!(f, "{}", parent.bottom)?; @@ -83,7 +107,7 @@ impl super::Function for Function { } } match &self.class { - Some(class) => match next { + Some(class) => match next.as_ref() { Some(next) => { if next.class.is_some() { if next.class.as_ref().unwrap().name == class.name { @@ -107,6 +131,14 @@ impl super::Function for Function { fn get_metadata(&self) -> HashMap<&str, String> { todo!() } + + fn matches(&self, filter: &LanguageFilter) -> bool { + if let LanguageFilter::Python(filt) = filter { + filt.matches(self) + } else { + false + } + } } #[derive(Debug, Clone)] pub struct Params { @@ -139,7 +171,7 @@ pub(crate) fn find_function_in_commit( commit: &str, file_path: &str, name: &str, -) -> Result, Box> { +) -> Result, Box> { let file_contents = crate::find_file_in_commit(commit, file_path)?; let ast = parser::parse_program(&file_contents)?; @@ -186,7 +218,7 @@ pub(crate) fn find_function_in_commit( t }) .collect::(); - let new_func = Function { + let new_func = PythonFunction { name: name.to_string(), returns: returns.as_ref().map(|x| x.name().to_string()), parameters: args.args.iter().map(|x| x.arg.to_string()).collect(), @@ -355,7 +387,7 @@ pub enum Filter { } impl Filter { - pub fn matches(&self, function: &Function) -> bool { + pub fn matches(&self, function: &PythonFunction) -> bool { match self { Self::FunctionInClass(class) => { function.class.as_ref().map_or(false, |x| x.name == *class) diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index a89bfe13..67fd43b5 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -5,9 +5,11 @@ use ra_ap_syntax::{ AstNode, SourceFile, SyntaxKind, }; +use super::LanguageFilter; + /// This holds the information about a single function each commit will have multiple of these. #[derive(Debug, Clone)] -pub struct Function { +pub struct RustFunction { pub(crate) name: String, /// The actual code of the function pub(crate) contents: String, @@ -31,18 +33,25 @@ pub struct Function { pub(crate) doc_comments: Vec, } -impl super::Function for Function { +impl super::Function for RustFunction { + fn matches(&self, filter: &LanguageFilter) -> bool { + if let LanguageFilter::Rust(filt) = filter { + filt.matches(self) + } else { + false + } + } /// This is a formater almost like the fmt you use for println!, but it takes a previous and next function. /// This is usefull for printing `CommitHistory` or a vector of functions, because if you use plain old fmt, you can get repeated lines impls, and parent function in your output. fn fmt_with_context( &self, f: &mut fmt::Formatter<'_>, - previous: Option<&Self>, - next: Option<&Self>, + previous: Box>, + next: Box>, ) -> fmt::Result { match &self.block { None => {} - Some(block) => match previous { + Some(block) => match previous.as_ref() { None => write!(f, "{}\n...\n", block.top)?, Some(previous_function) => match &previous_function.block { None => write!(f, "{}\n...\n", block.top)?, @@ -58,7 +67,7 @@ impl super::Function for Function { }; if !self.function.is_empty() { for i in &self.function { - match previous { + match previous.as_ref() { None => write!(f, "{}\n...\n", i.top)?, Some(previous_function) => { if previous_function @@ -77,7 +86,7 @@ impl super::Function for Function { write!(f, "{}", self.contents)?; if !self.function.is_empty() { for i in &self.function { - match next { + match next.as_ref() { None => write!(f, "\n...{}", i.bottom)?, Some(next_function) => { if next_function.function.iter().any(|x| x.lines == i.lines) { @@ -90,7 +99,7 @@ impl super::Function for Function { } match &self.block { None => {} - Some(block) => match next { + Some(block) => match next.as_ref() { None => write!(f, "\n...{}", block.bottom)?, Some(next_function) => match &next_function.block { None => write!(f, "\n...{}", block.bottom)?, @@ -135,9 +144,13 @@ impl super::Function for Function { }; map } + + fn get_lines(&self) -> (usize, usize) { + self.lines + } } -impl Function { +impl RustFunction { /// get the parent functions pub fn get_parent_function(&self) -> Vec { self.function.clone() @@ -149,7 +162,7 @@ impl Function { } } -impl fmt::Display for Function { +impl fmt::Display for RustFunction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.block { None => {} @@ -309,7 +322,7 @@ pub(crate) fn find_function_in_commit( commit: &str, file_path: &str, name: &str, -) -> Result, Box> { +) -> Result, Box> { let file_contents = crate::find_file_in_commit(commit, file_path)?; let mut functions = Vec::new(); get_function_asts(name, &file_contents, &mut functions); @@ -427,7 +440,7 @@ pub(crate) fn find_function_in_commit( }) .collect(); let contents = contents.trim_end().to_string(); - let function = Function { + let function = RustFunction { name: f.name().unwrap().to_string(), contents, block: parent_block, @@ -586,7 +599,7 @@ pub enum Filter { } impl Filter { - pub fn matches(&self, function: &Function) -> bool { + pub fn matches(&self, function: &RustFunction) -> bool { match self { Self::FunctionInBlock(block_type) => function .block diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index a067ed91..84e73d75 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -185,7 +185,7 @@ pub fn get_function_history( // check if file is a rust file if let FileType::Absolute(path) | FileType::Relative(path) = &file { match langs { - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] Language::C => { if !path.ends_with(".c") || !path.ends_with(".h") { Err(format!("file is not a c file: {}", path))?; @@ -310,7 +310,7 @@ fn find_function_in_commit_with_filetype( } FileType::None => { match langs { - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] Language::C => { if file.ends_with(".c") || file.ends_with(".h") { files.push(file); @@ -368,7 +368,7 @@ fn find_function_in_commit( types::FileType::Rust(functions, 0), )) } - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] Language::C => { let functions = languages::c::find_function_in_commit(commit, file_path, name)?; Ok(File::new( @@ -391,7 +391,7 @@ fn find_function_in_commit( types::FileType::Rust(functions, 0), )) } - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] Some("c" | "h") => { let functions = languages::c::find_function_in_commit(commit, file_path, name)?; Ok(File::new( @@ -556,7 +556,7 @@ mod tests { } #[test] - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] fn c_lang() { let now = Utc::now(); let output = get_function_history( diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index b3ecace1..46df6609 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -2,16 +2,182 @@ use chrono::{DateTime, FixedOffset}; use rayon::prelude::IntoParallelRefIterator; #[cfg(feature = "parallel")] use rayon::prelude::ParallelIterator; -use std::{collections::HashMap, error::Error, fmt}; +use std::{collections::HashMap, error::Error, fmt::{self, Formatter, Display}}; use crate::{ languages::{python, rust, Function, LanguageFilter}, Filter, }; -#[cfg(feature = "c-lang")] +#[cfg(feature = "c_lang")] use crate::languages::c; +pub mod new_ideas { + use std::{fmt::{self, Formatter, Display, Debug}, error::Error}; + + use enum_dispatch::enum_dispatch; + + use crate::{languages::{Language, Function, rust::{self, RustFunction}, python::{self, PythonFunction} , LanguageFilter}, Filter}; + + #[cfg(feature = "c_lang")] + use crate::languages::c; + #[derive(Debug, Clone)] + pub struct File { + pub(crate) path: String, + pub(crate) functions: Vec, + pub(crate) current_position: usize, + } + + impl File { + pub fn new(path: String, functions: Vec) -> File { + File { path, functions, current_position: 0 } + } + } + + impl Display for File { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + for (i, function) in self.functions.iter().enumerate() { + write!( + f, + "{}", + match i { + 0 => "", + _ => "\n...\n", + }, + )?; + let previous = match i { + 0 => None, + _ => self.functions.get(i - 1), + }; + let next = self.functions.get(i + 1); + function.fmt_with_context(f, Box::new(previous), Box::new(next))?; + } + Ok(()) + } + } + + + + + #[enum_dispatch] + pub trait FileTrait{ + fn get_path(&self) -> &str; + fn get_functions(&self) -> &Vec; + fn filter_by(&self, filter: Filter) -> Result, Box> { + let mut functions: Vec = self.get_functions().clone(); + match filter { + Filter::PLFilter(pl_filter) => { + functions = functions.into_iter().filter(|function| {function.matches(&pl_filter)}).collect(); + } + Filter::FunctionInLines(start, end) => { + functions = functions + .into_iter() + .filter(|function| { + let (start_line, end_line) = function.get_lines(); + start_line >= start && end_line <= end + }) + .collect(); + } + _ => { + return Err(format!("Filter {:?} not implemented", filter).into()); + } + + } + + Ok(File { path: self.get_path().to_string(), functions, current_position: 0 }) + } + } + #[enum_dispatch(FileTrait)] + #[derive(Debug, Clone)] + + pub enum FileType { + Python(PythonFile), + Rust(RustFile), + #[cfg(feature = "c_lang")] + C(CFile), + } + impl FileType { + pub fn filter_by(&self, filter: Filter) -> Result> { + match self { + FileType::Python(file) => { + let filtered_file = file.filter_by(filter)?; + Ok(FileType::Python(filtered_file)) + } + FileType::Rust(file) => { + let filtered_file = file.filter_by(filter)?; + Ok(FileType::Rust(filtered_file)) + } + #[cfg(feature = "c_lang")] + FileType::C(file) => { + let filtered_file = file.filter_by(filter)?; + Ok(FileType::C(filtered_file)) + } + } + } + } + type PythonFile = File; + impl FileTrait for PythonFile { + + fn get_path(&self) -> &str { + &self.path + } + fn get_functions(&self) -> &Vec { + &self.functions + } + } + + + type RustFile = File; + + impl FileTrait for RustFile { + + fn get_path(&self) -> &str { + &self.path + } + fn get_functions(&self) -> &Vec { + &self.functions + } + } + + #[cfg(feature = "c_lang")] + pub type CFile = File; + + #[cfg(feature = "c_lang")] + impl FileTrait for CFile { + fn get_path(&self) -> &str { + &self.path + } + fn get_functions(&self) -> &Vec { + &self.functions + } + } + impl Iterator for File { + type Item = T; + fn next(&mut self) -> Option { + self.functions.get(self.current_position).map(|function| { + self.current_position += 1; + function.clone() + }) + } + + } + + #[test] + fn test_file() { + let file: PythonFile = File::new("test.py".to_owned(), vec![]); + + + let file: FileType = file.into(); + // file.g + // let file = Box::new(file); + // file. + // assert_eq!(file. + // assert_eq!(file.get_functions().len(), 2); + // assert_eq!(file.get_functions()[0].get_name(), "test"); + // assert_eq!(file.get_functions()[1].get_name(), "test2"); + } + +} /// This is used to store each individual file in a commit and the associated functions in that file. #[derive(Debug, Clone)] pub struct File { @@ -94,7 +260,7 @@ impl File { } FileType::Python(vec, 0) } - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] FileType::C(functions, _) => { let mut vec = Vec::new(); for function in functions { @@ -119,7 +285,7 @@ impl File { } }; match &new_file.functions { - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] FileType::C(functions, _) => { if functions.is_empty() { return Err("No functions found for filter")?; @@ -145,8 +311,8 @@ impl File { } } -impl fmt::Display for File { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl Display for File { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { // write!(f, "{}", self.name) match &self.functions { FileType::Python(python, _) => { @@ -164,7 +330,7 @@ impl fmt::Display for File { _ => python.get(i - 1), }; let next = python.get(i + 1); - function.fmt_with_context(f, previous, next)?; + function.fmt_with_context(f, Box::new(previous), Box::new(next)); } } FileType::Rust(rust, _) => { @@ -182,10 +348,10 @@ impl fmt::Display for File { _ => rust.get(i - 1), }; let next = rust.get(i + 1); - function.fmt_with_context(f, previous, next)?; + function.fmt_with_context(f, Box::new(previous), Box::new(next)); } } - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] FileType::C(c, _) => { for (i, function) in c.iter().enumerate() { write!( @@ -201,7 +367,7 @@ impl fmt::Display for File { _ => c.get(i - 1), }; let next = c.get(i + 1); - function.fmt_with_context(f, previous, next)?; + function.fmt_with_context(f, Box::new(previous), Box::new(next)); } } }; @@ -210,9 +376,9 @@ impl fmt::Display for File { } pub enum FunctionType { - Python(python::Function), - Rust(rust::Function), - #[cfg(feature = "c-lang")] + Python(python::PythonFunction), + Rust(rust::RustFunction), + #[cfg(feature = "c_lang")] C(c::Function), } @@ -221,7 +387,7 @@ impl FunctionType { match self { Self::Python(python) => python.lines, Self::Rust(rust) => rust.lines, - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] Self::C(c) => c.lines, } } @@ -239,7 +405,7 @@ impl Iterator for File { python.get(current).map(|f| FunctionType::Python(f.clone())) } FileType::Rust(rust, _) => rust.get(current).map(|f| FunctionType::Rust(f.clone())), - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] FileType::C(c, _) => c.get(current).map(|f| FunctionType::C(f.clone())), } } @@ -248,10 +414,10 @@ impl Iterator for File { #[derive(Debug, Clone)] pub enum FileType { /// The python language - Python(Vec, usize), + Python(Vec, usize), /// The rust language - Rust(Vec, usize), - #[cfg(feature = "c-lang")] + Rust(Vec, usize), + #[cfg(feature = "c_lang")] /// c language C(Vec, usize), } @@ -269,7 +435,7 @@ impl Iterator for FileType { *pos += 1; FunctionType::Rust(f.clone()) }), - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] Self::C(c, pos) => c.get(*pos).map(|f| { *pos += 1; FunctionType::C(f.clone()) @@ -284,7 +450,7 @@ impl FileType { Self::Rust(rust, _) => rust .get(index) .map(|function| FunctionType::Rust(function.clone())), - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] Self::C(c, _) => c .get(index) .map(|function| FunctionType::C(function.clone())), @@ -293,9 +459,9 @@ impl FileType { .map(|function| FunctionType::Python(function.clone())), } } - #[cfg(feature = "c-lang")] + #[cfg(feature = "c_lang")] pub fn get_current< - T: Clone + From + From + From, + T: Clone + From + From + From, >( &self, ) -> Vec { @@ -312,8 +478,8 @@ impl FileType { } } - #[cfg(not(feature = "c-lang"))] - pub fn get_current + From>(&self) -> Vec { + #[cfg(not(feature = "c_lang"))] + pub fn get_current + From>(&self) -> Vec { match self { Self::Python(python, _pos) => python .iter() @@ -468,8 +634,8 @@ impl Iterator for Commit { } } -impl fmt::Display for Commit { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl Display for Commit { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { writeln!(f, "{}", self.files[self.current_pos])?; Ok(()) } @@ -621,8 +787,8 @@ impl FunctionHistory { } } -impl fmt::Display for FunctionHistory { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl Display for FunctionHistory { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { writeln!(f, "{}", self.commit_history[self.current_pos])?; Ok(()) } From a3373f14e2735e1f6c15abd81b14ac5e8ab27ed4 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Fri, 7 Oct 2022 16:52:43 -0400 Subject: [PATCH 033/172] pushing this mess just to save it --- git-function-history-lib/src/languages/c.rs | 4 +- git-function-history-lib/src/languages/mod.rs | 6 +- .../src/languages/python.rs | 4 +- .../src/languages/rust.rs | 4 +- git-function-history-lib/src/lib.rs | 4 + git-function-history-lib/src/types.rs | 423 +++++++++++++++++- 6 files changed, 416 insertions(+), 29 deletions(-) diff --git a/git-function-history-lib/src/languages/c.rs b/git-function-history-lib/src/languages/c.rs index 2a86bba5..68bfb8c5 100644 --- a/git-function-history-lib/src/languages/c.rs +++ b/git-function-history-lib/src/languages/c.rs @@ -35,8 +35,8 @@ impl super::Function for CFunction { fn fmt_with_context( &self, f: &mut std::fmt::Formatter<'_>, - previous: Box>, - next: Box>, + previous: Option<&Self>, + next: Option<&Self>, ) -> std::fmt::Result { todo!() } diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 13fd0361..e4b08db3 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -51,12 +51,12 @@ pub mod c; pub mod python; pub mod rust; -pub trait Function: fmt::Debug + Clone + fmt::Display { +pub trait Function: fmt::Debug + fmt::Display { fn fmt_with_context( &self, f: &mut fmt::Formatter<'_>, - previous: Box>, - next: Box>, + previous: Option<&Self>, + next: Option<&Self>, ) -> fmt::Result; fn get_metadata(&self) -> HashMap<&str, String>; diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index a66367e5..09adf2fd 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -49,8 +49,8 @@ impl super::Function for PythonFunction { fn fmt_with_context( &self, f: &mut std::fmt::Formatter<'_>, - previous: Box>, - next: Box>, + previous: Option<&Self>, + next: Option<&Self>, ) -> std::fmt::Result { match &self.class { Some(class) => match previous.as_ref() { diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 67fd43b5..126fb9dc 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -46,8 +46,8 @@ impl super::Function for RustFunction { fn fmt_with_context( &self, f: &mut fmt::Formatter<'_>, - previous: Box>, - next: Box>, + previous: Option<&Self>, + next: Option<&Self>, ) -> fmt::Result { match &self.block { None => {} diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 84e73d75..e393b5a3 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -553,6 +553,10 @@ mod tests { Err(e) => println!("{}", e), } assert!(output.is_ok()); + let output = output.unwrap(); + let commit = output.get_commit(); + let file = commit.get_file(); + let functions = file.get_functions(); } #[test] diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 46df6609..cee243eb 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -5,7 +5,7 @@ use rayon::prelude::ParallelIterator; use std::{collections::HashMap, error::Error, fmt::{self, Formatter, Display}}; use crate::{ - languages::{python, rust, Function, LanguageFilter}, + languages::{python::{self, PythonFunction}, rust::{self, RustFunction}, Function, LanguageFilter}, Filter, }; @@ -13,7 +13,7 @@ use crate::{ use crate::languages::c; pub mod new_ideas { - use std::{fmt::{self, Formatter, Display, Debug}, error::Error}; + use std::{fmt::{self, Formatter, Display, Debug}, error::Error, collections::HashMap}; use enum_dispatch::enum_dispatch; @@ -22,19 +22,19 @@ pub mod new_ideas { #[cfg(feature = "c_lang")] use crate::languages::c; #[derive(Debug, Clone)] - pub struct File { + pub struct File { pub(crate) path: String, pub(crate) functions: Vec, pub(crate) current_position: usize, } - impl File { + impl File { pub fn new(path: String, functions: Vec) -> File { File { path, functions, current_position: 0 } } } - impl Display for File { + impl Display for File { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { for (i, function) in self.functions.iter().enumerate() { write!( @@ -50,21 +50,104 @@ pub mod new_ideas { _ => self.functions.get(i - 1), }; let next = self.functions.get(i + 1); - function.fmt_with_context(f, Box::new(previous), Box::new(next))?; + function.fmt_with_context(f, previous, next)?; } Ok(()) } } + #[derive(Debug, Clone)] + pub enum FunctionType { + Rust(RustFunction), + Python(PythonFunction), + #[cfg(feature = "c_lang")] + C(CFunction), + } + impl Display for FunctionType { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::Rust(rust) => std::fmt::Display::fmt(&rust, f), + Self::Python(python) => std::fmt::Display::fmt(&python, f), + #[cfg(feature = "c_lang")] + Self::C(c) => c.fmt(f), + } + } + } + // impl Into for &RustFunction { + // fn into(self) -> FunctionType { + // FunctionType::Rust(self.clone()) + // } + // } + + impl std::convert::From<&FunctionType > for &RustFunction { + fn from(function: &FunctionType) -> Self { + match function { + FunctionType::Rust(rust) => rust, + _ => panic!("Cannot convert to RustFunction"), + } + } + } + impl std::convert::From<&FunctionType > for &PythonFunction { + fn from(function: &FunctionType) -> Self { + match function { + FunctionType::Python(python) => python, + _ => panic!("Cannot convert to PythonFunction"), + } + } + } + impl Function for FunctionType { + fn fmt_with_context( + &self, + f: &mut Formatter<'_>, + previous: Option<&Self>, + next: Option<&Self>, + ) -> fmt::Result { + match self { + Self::Rust(rust) => rust.fmt_with_context(f, previous.map(|p| p.into()), next.map(|n| n.into())), + Self::Python(python) => python.fmt_with_context(f, previous.map(|x| x.into()), next.map(|x| x.into())), + #[cfg(feature = "c_lang")] + Self::C(c) => c.fmt_with_context(f, previous, next), + } + } + + + fn get_metadata(&self) -> HashMap<&str, String> { + match self { + Self::Rust(rust) => rust.get_metadata(), + Self::Python(python) => python.get_metadata(), + #[cfg(feature = "c_lang")] + Self::C(c) => c.get_metadata(), + } + } + + fn get_lines(&self) -> (usize, usize) { + match self { + Self::Rust(rust) => rust.get_lines(), + Self::Python(python) => python.get_lines(), + #[cfg(feature = "c_lang")] + Self::C(c) => c.get_lines(), + } + } + + fn matches(&self, filter: &LanguageFilter) -> bool { + match self { + Self::Rust(rust) => rust.matches(filter), + Self::Python(python) => python.matches(filter), + #[cfg(feature = "c_lang")] + Self::C(c) => c.matches(filter), + } + } + } #[enum_dispatch] - pub trait FileTrait{ + pub trait FileTrait { + // type Item:; fn get_path(&self) -> &str; - fn get_functions(&self) -> &Vec; - fn filter_by(&self, filter: Filter) -> Result, Box> { - let mut functions: Vec = self.get_functions().clone(); + fn get_functions(&self) -> &Vec; + fn filter_by(&self, filter: Filter) -> Result, Box> { + let mut functions: Vec = self.get_functions().clone(); match filter { Filter::PLFilter(pl_filter) => { functions = functions.into_iter().filter(|function| {function.matches(&pl_filter)}).collect(); @@ -87,7 +170,7 @@ pub mod new_ideas { Ok(File { path: self.get_path().to_string(), functions, current_position: 0 }) } } - #[enum_dispatch(FileTrait)] + #[enum_dispatch(FileTrait)] #[derive(Debug, Clone)] pub enum FileType { @@ -101,7 +184,7 @@ pub mod new_ideas { match self { FileType::Python(file) => { let filtered_file = file.filter_by(filter)?; - Ok(FileType::Python(filtered_file)) + Ok(filtered_file) } FileType::Rust(file) => { let filtered_file = file.filter_by(filter)?; @@ -116,7 +199,8 @@ pub mod new_ideas { } } type PythonFile = File; - impl FileTrait for PythonFile { + impl FileTrait for PythonFile { + // type Item = PythonFunction; fn get_path(&self) -> &str { &self.path @@ -129,8 +213,8 @@ pub mod new_ideas { type RustFile = File; - impl FileTrait for RustFile { - + impl FileTrait for RustFile { + // type Item = RustFunction; fn get_path(&self) -> &str { &self.path } @@ -151,7 +235,7 @@ pub mod new_ideas { &self.functions } } - impl Iterator for File { + impl Iterator for File { type Item = T; fn next(&mut self) -> Option { self.functions.get(self.current_position).map(|function| { @@ -162,13 +246,41 @@ pub mod new_ideas { } + // impl Into for PythonFile { + // fn into(self) -> FileType { + // FileType::Python(self) + // } + // } + + + + // impl FileTrait for FileType { + // type Item = + // fn get_path(&self) -> &str { + // match self { + // FileType::Python(file) => file.get_path(), + // FileType::Rust(file) => file.get_path(), + // #[cfg(feature = "c_lang")] + // FileType::C(file) => file.get_path(), + // } + // } + // fn get_functions(&self) -> &Vec { + // match self { + // FileType::Python(file) => file.get_functions(), + // FileType::Rust(file) => file.get_functions(), + // #[cfg(feature = "c_lang")] + // FileType::C(file) => file.get_functions(), + // } + // } + // } + #[test] fn test_file() { let file: PythonFile = File::new("test.py".to_owned(), vec![]); let file: FileType = file.into(); - // file.g + // file. // let file = Box::new(file); // file. // assert_eq!(file. @@ -178,6 +290,277 @@ pub mod new_ideas { } } + + +// pub mod new_new_ideas { + +// use std::{fmt::{self, Formatter, Display, Debug}, error::Error, collections::HashMap}; + +// use chrono::{FixedOffset, DateTime}; +// use enum_dispatch::enum_dispatch; + +// use crate::{languages::{Language, Function, rust::{self, RustFunction}, python::{self, PythonFunction} , LanguageFilter}, Filter}; + +// #[cfg(feature = "c_lang")] +// use crate::languages::c; + +// use super::Directions; +// #[derive(Debug, Clone)] +// pub struct File { +// pub(crate) path: String, +// pub(crate) functions: Vec, +// pub(crate) current_position: usize, +// } + +// impl File { +// pub fn new(path: String, functions: Vec) -> File { +// File { path, functions, current_position: 0 } +// } +// } + +// impl Display for File { +// fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +// for (i, function) in self.functions.iter().enumerate() { +// write!( +// f, +// "{}", +// match i { +// 0 => "", +// _ => "\n...\n", +// }, +// )?; +// let previous = match i { +// 0 => None, +// _ => self.functions.get(i - 1), +// }; +// let next = self.functions.get(i + 1); +// function.fmt_with_context(f, Box::new(previous), Box::new(next))?; +// } +// Ok(()) +// } +// } + + + +// // #[enum_dispatch] +// pub trait FileTrait { +// type Item: Function + Display + Debug + Clone; +// fn get_path(&self) -> &str; +// fn get_functions(&self) -> &Vec; +// fn filter_by(&self, filter: Filter) -> Result, Box> { +// let mut functions: Vec = self.get_functions().clone(); +// match filter { +// Filter::PLFilter(pl_filter) => { +// functions = functions.into_iter().filter(|function| {function.matches(&pl_filter)}).collect(); +// } +// Filter::FunctionInLines(start, end) => { +// functions = functions +// .into_iter() +// .filter(|function| { +// let (start_line, end_line) = function.get_lines(); +// start_line >= start && end_line <= end +// }) +// .collect(); +// } +// _ => { +// return Err(format!("Filter {:?} not implemented", filter).into()); +// } + +// } + +// Ok(File { path: self.get_path().to_string(), functions, current_position: 0 }) +// } +// } + +// type PythonFile = File; +// impl FileTrait for PythonFile { +// type Item = PythonFunction; + +// fn get_path(&self) -> &str { +// &self.path +// } +// fn get_functions(&self) -> &Vec { +// &self.functions +// } +// } + + +// type RustFile = File; + +// impl FileTrait for RustFile { +// type Item = RustFunction; +// fn get_path(&self) -> &str { +// &self.path +// } +// fn get_functions(&self) -> &Vec { +// &self.functions +// } +// } + +// #[cfg(feature = "c_lang")] +// pub type CFile = File; + +// #[cfg(feature = "c_lang")] +// impl FileTrait for CFile { +// fn get_path(&self) -> &str { +// &self.path +// } +// fn get_functions(&self) -> &Vec { +// &self.functions +// } +// } +// impl Iterator for File { +// type Item = T; +// fn next(&mut self) -> Option { +// self.functions.get(self.current_position).map(|function| { +// self.current_position += 1; +// function.clone() +// }) +// } + +// } + + +// #[derive(Debug, Clone)] +// pub struct Commit { +// commit_hash: String, +// python_files: Vec, +// rust_files: Vec, +// #[cfg(feature = "c_lang")] +// c_files: Vec, +// pub(crate) date: DateTime, +// current_iter_pos: usize, +// current_pos: usize, +// author: String, +// email: String, +// message: String, +// } + + + +// impl Commit { +// /// Create a new `Commit` with the given `commit_hash`, functions, and date. +// pub fn new( +// commit_hash: String, +// python_files: Vec, +// rust_files: Vec, +// #[cfg(feature = "c_lang")] c_files: Vec, +// date: &str, +// author: String, +// email: String, +// message: String, +// ) -> Self { +// Self { +// commit_hash, +// python_files, +// rust_files, +// #[cfg(feature = "c_lang")] +// c_files, +// date: DateTime::parse_from_rfc2822(&date).expect("Failed to parse date"), +// current_pos: 0, +// current_iter_pos: 0, +// author, +// email, +// message, +// } +// } + +// /// sets the current file to the next file if possible +// pub fn move_forward(&mut self) { +// if self.current_pos >= self.files.len() - 1 { +// return; +// } +// self.current_pos += 1; +// } + +// /// sets the current file to the previous file if possible +// pub fn move_back(&mut self) { +// if self.current_pos == 0 { +// return; +// } +// self.current_pos -= 1; +// } + +// /// returns a hashmap containing the commits metadata +// /// inlcuding the `commit hash`, `date`, and `file` +// pub fn get_metadata(&self) -> HashMap { +// let mut map = HashMap::new(); +// map.insert("commit hash".to_string(), self.commit_hash.clone()); +// map.insert("date".to_string(), self.date.to_rfc2822()); +// map.insert( +// "file".to_string(), +// self.files[self.current_pos].name.clone(), +// ); +// map +// } + +// /// returns the current file +// pub fn get_file(&self) -> &File { +// &self.files[self.current_pos] +// } + +// /// returns the current file (mutable) +// pub fn get_file_mut(&mut self) -> &mut File { +// &mut self.files[self.current_pos] +// } + +// /// tells you in which directions you can move through the files in the commit +// pub fn get_move_direction(&self) -> Directions { +// match self.current_pos { +// 0 if self.files.len() == 1 => Directions::None, +// 0 => Directions::Forward, +// x if x == self.files.len() - 1 => Directions::Back, +// _ => Directions::Both, +// } +// } + +// /// returns a new `Commit` by filtering the current one by the filter specified (does not modify the current one). +// /// +// /// valid filters are: `Filter::FunctionInLines`, and `Filter::FileAbsolute`, `Filter::FileRelative`, and `Filter::Directory`. +// pub fn filter_by(&self, filter: &Filter) -> Result> { +// match filter { +// Filter::FileAbsolute(_) +// | Filter::FileRelative(_) +// | Filter::Directory(_) +// | Filter::FunctionInLines(..) +// | Filter::PLFilter(_) => {} +// Filter::None => { +// return Ok(self.clone()); +// } +// _ => Err("Invalid filter")?, +// } +// #[cfg(feature = "parallel")] +// let t = self.files.iter(); +// #[cfg(not(feature = "parallel"))] +// let t = self.files.iter(); +// let vec: Vec<_> = t +// .filter(|f| match filter { +// Filter::FileAbsolute(file) => f.name == *file, +// Filter::FileRelative(file) => f.name.ends_with(file), +// Filter::Directory(dir) => f.name.contains(dir), +// Filter::FunctionInLines(..) | Filter::PLFilter(_) => f.filter_by(filter).is_ok(), +// Filter::None => true, +// _ => false, +// }) +// .cloned() +// .collect(); + +// if vec.is_empty() { +// return Err("No files found for filter")?; +// } +// Ok(Self { +// commit_hash: self.commit_hash.clone(), +// files: vec, +// date: self.date, +// current_pos: 0, +// current_iter_pos: 0, +// author: self.author.clone(), +// email: self.email.clone(), +// message: self.message.clone(), +// }) +// } +// } +// } /// This is used to store each individual file in a commit and the associated functions in that file. #[derive(Debug, Clone)] pub struct File { @@ -330,7 +713,7 @@ impl Display for File { _ => python.get(i - 1), }; let next = python.get(i + 1); - function.fmt_with_context(f, Box::new(previous), Box::new(next)); + function.fmt_with_context(f, previous,next); } } FileType::Rust(rust, _) => { @@ -348,7 +731,7 @@ impl Display for File { _ => rust.get(i - 1), }; let next = rust.get(i + 1); - function.fmt_with_context(f, Box::new(previous), Box::new(next)); + function.fmt_with_context(f, previous,next); } } #[cfg(feature = "c_lang")] @@ -367,7 +750,7 @@ impl Display for File { _ => c.get(i - 1), }; let next = c.get(i + 1); - function.fmt_with_context(f, Box::new(previous), Box::new(next)); + function.fmt_with_context(f, previous,next); } } }; From a7adde19b09849916a416d6944d785df4c612f7c Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Fri, 7 Oct 2022 16:53:28 -0400 Subject: [PATCH 034/172] back to normal for now --- git-function-history-lib/src/types.rs | 549 -------------------------- 1 file changed, 549 deletions(-) diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index cee243eb..cd707ed1 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -11,556 +11,7 @@ use crate::{ #[cfg(feature = "c_lang")] use crate::languages::c; -pub mod new_ideas { - use std::{fmt::{self, Formatter, Display, Debug}, error::Error, collections::HashMap}; - - use enum_dispatch::enum_dispatch; - - use crate::{languages::{Language, Function, rust::{self, RustFunction}, python::{self, PythonFunction} , LanguageFilter}, Filter}; - - #[cfg(feature = "c_lang")] - use crate::languages::c; - #[derive(Debug, Clone)] - pub struct File { - pub(crate) path: String, - pub(crate) functions: Vec, - pub(crate) current_position: usize, - } - - impl File { - pub fn new(path: String, functions: Vec) -> File { - File { path, functions, current_position: 0 } - } - } - - impl Display for File { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - for (i, function) in self.functions.iter().enumerate() { - write!( - f, - "{}", - match i { - 0 => "", - _ => "\n...\n", - }, - )?; - let previous = match i { - 0 => None, - _ => self.functions.get(i - 1), - }; - let next = self.functions.get(i + 1); - function.fmt_with_context(f, previous, next)?; - } - Ok(()) - } - } - #[derive(Debug, Clone)] - pub enum FunctionType { - Rust(RustFunction), - Python(PythonFunction), - #[cfg(feature = "c_lang")] - C(CFunction), - } - - impl Display for FunctionType { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - Self::Rust(rust) => std::fmt::Display::fmt(&rust, f), - Self::Python(python) => std::fmt::Display::fmt(&python, f), - #[cfg(feature = "c_lang")] - Self::C(c) => c.fmt(f), - } - } - } - // impl Into for &RustFunction { - // fn into(self) -> FunctionType { - // FunctionType::Rust(self.clone()) - // } - // } - - impl std::convert::From<&FunctionType > for &RustFunction { - fn from(function: &FunctionType) -> Self { - match function { - FunctionType::Rust(rust) => rust, - _ => panic!("Cannot convert to RustFunction"), - } - } - } - impl std::convert::From<&FunctionType > for &PythonFunction { - fn from(function: &FunctionType) -> Self { - match function { - FunctionType::Python(python) => python, - _ => panic!("Cannot convert to PythonFunction"), - } - } - } - impl Function for FunctionType { - fn fmt_with_context( - &self, - f: &mut Formatter<'_>, - previous: Option<&Self>, - next: Option<&Self>, - ) -> fmt::Result { - match self { - Self::Rust(rust) => rust.fmt_with_context(f, previous.map(|p| p.into()), next.map(|n| n.into())), - Self::Python(python) => python.fmt_with_context(f, previous.map(|x| x.into()), next.map(|x| x.into())), - #[cfg(feature = "c_lang")] - Self::C(c) => c.fmt_with_context(f, previous, next), - } - } - - - - fn get_metadata(&self) -> HashMap<&str, String> { - match self { - Self::Rust(rust) => rust.get_metadata(), - Self::Python(python) => python.get_metadata(), - #[cfg(feature = "c_lang")] - Self::C(c) => c.get_metadata(), - } - } - - fn get_lines(&self) -> (usize, usize) { - match self { - Self::Rust(rust) => rust.get_lines(), - Self::Python(python) => python.get_lines(), - #[cfg(feature = "c_lang")] - Self::C(c) => c.get_lines(), - } - } - - fn matches(&self, filter: &LanguageFilter) -> bool { - match self { - Self::Rust(rust) => rust.matches(filter), - Self::Python(python) => python.matches(filter), - #[cfg(feature = "c_lang")] - Self::C(c) => c.matches(filter), - } - } - } - - - #[enum_dispatch] - pub trait FileTrait { - // type Item:; - fn get_path(&self) -> &str; - fn get_functions(&self) -> &Vec; - fn filter_by(&self, filter: Filter) -> Result, Box> { - let mut functions: Vec = self.get_functions().clone(); - match filter { - Filter::PLFilter(pl_filter) => { - functions = functions.into_iter().filter(|function| {function.matches(&pl_filter)}).collect(); - } - Filter::FunctionInLines(start, end) => { - functions = functions - .into_iter() - .filter(|function| { - let (start_line, end_line) = function.get_lines(); - start_line >= start && end_line <= end - }) - .collect(); - } - _ => { - return Err(format!("Filter {:?} not implemented", filter).into()); - } - - } - - Ok(File { path: self.get_path().to_string(), functions, current_position: 0 }) - } - } - #[enum_dispatch(FileTrait)] - #[derive(Debug, Clone)] - - pub enum FileType { - Python(PythonFile), - Rust(RustFile), - #[cfg(feature = "c_lang")] - C(CFile), - } - impl FileType { - pub fn filter_by(&self, filter: Filter) -> Result> { - match self { - FileType::Python(file) => { - let filtered_file = file.filter_by(filter)?; - Ok(filtered_file) - } - FileType::Rust(file) => { - let filtered_file = file.filter_by(filter)?; - Ok(FileType::Rust(filtered_file)) - } - #[cfg(feature = "c_lang")] - FileType::C(file) => { - let filtered_file = file.filter_by(filter)?; - Ok(FileType::C(filtered_file)) - } - } - } - } - type PythonFile = File; - impl FileTrait for PythonFile { - // type Item = PythonFunction; - - fn get_path(&self) -> &str { - &self.path - } - fn get_functions(&self) -> &Vec { - &self.functions - } - } - - - type RustFile = File; - - impl FileTrait for RustFile { - // type Item = RustFunction; - fn get_path(&self) -> &str { - &self.path - } - fn get_functions(&self) -> &Vec { - &self.functions - } - } - - #[cfg(feature = "c_lang")] - pub type CFile = File; - - #[cfg(feature = "c_lang")] - impl FileTrait for CFile { - fn get_path(&self) -> &str { - &self.path - } - fn get_functions(&self) -> &Vec { - &self.functions - } - } - impl Iterator for File { - type Item = T; - fn next(&mut self) -> Option { - self.functions.get(self.current_position).map(|function| { - self.current_position += 1; - function.clone() - }) - } - - } - - // impl Into for PythonFile { - // fn into(self) -> FileType { - // FileType::Python(self) - // } - // } - - - - // impl FileTrait for FileType { - // type Item = - // fn get_path(&self) -> &str { - // match self { - // FileType::Python(file) => file.get_path(), - // FileType::Rust(file) => file.get_path(), - // #[cfg(feature = "c_lang")] - // FileType::C(file) => file.get_path(), - // } - // } - // fn get_functions(&self) -> &Vec { - // match self { - // FileType::Python(file) => file.get_functions(), - // FileType::Rust(file) => file.get_functions(), - // #[cfg(feature = "c_lang")] - // FileType::C(file) => file.get_functions(), - // } - // } - // } - - #[test] - fn test_file() { - let file: PythonFile = File::new("test.py".to_owned(), vec![]); - - - let file: FileType = file.into(); - // file. - // let file = Box::new(file); - // file. - // assert_eq!(file. - // assert_eq!(file.get_functions().len(), 2); - // assert_eq!(file.get_functions()[0].get_name(), "test"); - // assert_eq!(file.get_functions()[1].get_name(), "test2"); - } - -} - - -// pub mod new_new_ideas { - -// use std::{fmt::{self, Formatter, Display, Debug}, error::Error, collections::HashMap}; - -// use chrono::{FixedOffset, DateTime}; -// use enum_dispatch::enum_dispatch; - -// use crate::{languages::{Language, Function, rust::{self, RustFunction}, python::{self, PythonFunction} , LanguageFilter}, Filter}; - -// #[cfg(feature = "c_lang")] -// use crate::languages::c; - -// use super::Directions; -// #[derive(Debug, Clone)] -// pub struct File { -// pub(crate) path: String, -// pub(crate) functions: Vec, -// pub(crate) current_position: usize, -// } - -// impl File { -// pub fn new(path: String, functions: Vec) -> File { -// File { path, functions, current_position: 0 } -// } -// } - -// impl Display for File { -// fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { -// for (i, function) in self.functions.iter().enumerate() { -// write!( -// f, -// "{}", -// match i { -// 0 => "", -// _ => "\n...\n", -// }, -// )?; -// let previous = match i { -// 0 => None, -// _ => self.functions.get(i - 1), -// }; -// let next = self.functions.get(i + 1); -// function.fmt_with_context(f, Box::new(previous), Box::new(next))?; -// } -// Ok(()) -// } -// } - - - -// // #[enum_dispatch] -// pub trait FileTrait { -// type Item: Function + Display + Debug + Clone; -// fn get_path(&self) -> &str; -// fn get_functions(&self) -> &Vec; -// fn filter_by(&self, filter: Filter) -> Result, Box> { -// let mut functions: Vec = self.get_functions().clone(); -// match filter { -// Filter::PLFilter(pl_filter) => { -// functions = functions.into_iter().filter(|function| {function.matches(&pl_filter)}).collect(); -// } -// Filter::FunctionInLines(start, end) => { -// functions = functions -// .into_iter() -// .filter(|function| { -// let (start_line, end_line) = function.get_lines(); -// start_line >= start && end_line <= end -// }) -// .collect(); -// } -// _ => { -// return Err(format!("Filter {:?} not implemented", filter).into()); -// } - -// } - -// Ok(File { path: self.get_path().to_string(), functions, current_position: 0 }) -// } -// } - -// type PythonFile = File; -// impl FileTrait for PythonFile { -// type Item = PythonFunction; - -// fn get_path(&self) -> &str { -// &self.path -// } -// fn get_functions(&self) -> &Vec { -// &self.functions -// } -// } - - -// type RustFile = File; - -// impl FileTrait for RustFile { -// type Item = RustFunction; -// fn get_path(&self) -> &str { -// &self.path -// } -// fn get_functions(&self) -> &Vec { -// &self.functions -// } -// } - -// #[cfg(feature = "c_lang")] -// pub type CFile = File; - -// #[cfg(feature = "c_lang")] -// impl FileTrait for CFile { -// fn get_path(&self) -> &str { -// &self.path -// } -// fn get_functions(&self) -> &Vec { -// &self.functions -// } -// } -// impl Iterator for File { -// type Item = T; -// fn next(&mut self) -> Option { -// self.functions.get(self.current_position).map(|function| { -// self.current_position += 1; -// function.clone() -// }) -// } - -// } - - -// #[derive(Debug, Clone)] -// pub struct Commit { -// commit_hash: String, -// python_files: Vec, -// rust_files: Vec, -// #[cfg(feature = "c_lang")] -// c_files: Vec, -// pub(crate) date: DateTime, -// current_iter_pos: usize, -// current_pos: usize, -// author: String, -// email: String, -// message: String, -// } - - - -// impl Commit { -// /// Create a new `Commit` with the given `commit_hash`, functions, and date. -// pub fn new( -// commit_hash: String, -// python_files: Vec, -// rust_files: Vec, -// #[cfg(feature = "c_lang")] c_files: Vec, -// date: &str, -// author: String, -// email: String, -// message: String, -// ) -> Self { -// Self { -// commit_hash, -// python_files, -// rust_files, -// #[cfg(feature = "c_lang")] -// c_files, -// date: DateTime::parse_from_rfc2822(&date).expect("Failed to parse date"), -// current_pos: 0, -// current_iter_pos: 0, -// author, -// email, -// message, -// } -// } - -// /// sets the current file to the next file if possible -// pub fn move_forward(&mut self) { -// if self.current_pos >= self.files.len() - 1 { -// return; -// } -// self.current_pos += 1; -// } - -// /// sets the current file to the previous file if possible -// pub fn move_back(&mut self) { -// if self.current_pos == 0 { -// return; -// } -// self.current_pos -= 1; -// } - -// /// returns a hashmap containing the commits metadata -// /// inlcuding the `commit hash`, `date`, and `file` -// pub fn get_metadata(&self) -> HashMap { -// let mut map = HashMap::new(); -// map.insert("commit hash".to_string(), self.commit_hash.clone()); -// map.insert("date".to_string(), self.date.to_rfc2822()); -// map.insert( -// "file".to_string(), -// self.files[self.current_pos].name.clone(), -// ); -// map -// } - -// /// returns the current file -// pub fn get_file(&self) -> &File { -// &self.files[self.current_pos] -// } - -// /// returns the current file (mutable) -// pub fn get_file_mut(&mut self) -> &mut File { -// &mut self.files[self.current_pos] -// } - -// /// tells you in which directions you can move through the files in the commit -// pub fn get_move_direction(&self) -> Directions { -// match self.current_pos { -// 0 if self.files.len() == 1 => Directions::None, -// 0 => Directions::Forward, -// x if x == self.files.len() - 1 => Directions::Back, -// _ => Directions::Both, -// } -// } - -// /// returns a new `Commit` by filtering the current one by the filter specified (does not modify the current one). -// /// -// /// valid filters are: `Filter::FunctionInLines`, and `Filter::FileAbsolute`, `Filter::FileRelative`, and `Filter::Directory`. -// pub fn filter_by(&self, filter: &Filter) -> Result> { -// match filter { -// Filter::FileAbsolute(_) -// | Filter::FileRelative(_) -// | Filter::Directory(_) -// | Filter::FunctionInLines(..) -// | Filter::PLFilter(_) => {} -// Filter::None => { -// return Ok(self.clone()); -// } -// _ => Err("Invalid filter")?, -// } -// #[cfg(feature = "parallel")] -// let t = self.files.iter(); -// #[cfg(not(feature = "parallel"))] -// let t = self.files.iter(); -// let vec: Vec<_> = t -// .filter(|f| match filter { -// Filter::FileAbsolute(file) => f.name == *file, -// Filter::FileRelative(file) => f.name.ends_with(file), -// Filter::Directory(dir) => f.name.contains(dir), -// Filter::FunctionInLines(..) | Filter::PLFilter(_) => f.filter_by(filter).is_ok(), -// Filter::None => true, -// _ => false, -// }) -// .cloned() -// .collect(); - -// if vec.is_empty() { -// return Err("No files found for filter")?; -// } -// Ok(Self { -// commit_hash: self.commit_hash.clone(), -// files: vec, -// date: self.date, -// current_pos: 0, -// current_iter_pos: 0, -// author: self.author.clone(), -// email: self.email.clone(), -// message: self.message.clone(), -// }) -// } -// } -// } /// This is used to store each individual file in a commit and the associated functions in that file. #[derive(Debug, Clone)] pub struct File { From 45f07a8cfe49191fd81d9c3e4125b7b002d32982 Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Sun, 9 Oct 2022 03:54:45 -0400 Subject: [PATCH 035/172] made working idea based on what i failed to do before by making function trait object safe --- .../src/languages/python.rs | 5 +- .../src/languages/rust.rs | 4 +- git-function-history-lib/src/lib.rs | 15 +- git-function-history-lib/src/new_types.rs | 303 ++++++++++++++++++ structure.txt | 20 ++ 5 files changed, 334 insertions(+), 13 deletions(-) create mode 100644 git-function-history-lib/src/new_types.rs create mode 100644 structure.txt diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 09adf2fd..2ae57961 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -168,11 +168,10 @@ pub struct ParentFunction { } pub(crate) fn find_function_in_commit( - commit: &str, - file_path: &str, + file_contents: &str, + name: &str, ) -> Result, Box> { - let file_contents = crate::find_file_in_commit(commit, file_path)?; let ast = parser::parse_program(&file_contents)?; let mut functions = vec![]; diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 126fb9dc..b18fd3ef 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -319,11 +319,9 @@ impl fmt::Display for BlockType { #[allow(clippy::too_many_lines)] // TODO: split this function into smaller functions pub(crate) fn find_function_in_commit( - commit: &str, - file_path: &str, + file_contents: &str, name: &str, ) -> Result, Box> { - let file_contents = crate::find_file_in_commit(commit, file_path)?; let mut functions = Vec::new(); get_function_asts(name, &file_contents, &mut functions); let mut starts = file_contents diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index e393b5a3..2f2a3e85 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -13,7 +13,7 @@ clippy::missing_errors_doc, clippy::return_self_not_must_use )] - +pub mod new_types; pub mod languages; /// Different types that can extracted from the result of `get_function_history`. pub mod types; @@ -360,9 +360,10 @@ fn find_function_in_commit( name: &str, langs: Language, ) -> Result> { + let fc = find_file_in_commit(commit, file_path)?; match langs { Language::Rust => { - let functions = rust::find_function_in_commit(commit, file_path, name)?; + let functions = rust::find_function_in_commit(&fc, name)?; Ok(File::new( file_path.to_string(), types::FileType::Rust(functions, 0), @@ -370,14 +371,14 @@ fn find_function_in_commit( } #[cfg(feature = "c_lang")] Language::C => { - let functions = languages::c::find_function_in_commit(commit, file_path, name)?; + let functions = languages::c::find_function_in_commit(&fc, name)?; Ok(File::new( file_path.to_string(), types::FileType::C(functions, 0), )) } Language::Python => { - let functions = languages::python::find_function_in_commit(commit, file_path, name)?; + let functions = languages::python::find_function_in_commit(&fc, name)?; Ok(File::new( file_path.to_string(), types::FileType::Python(functions, 0), @@ -385,7 +386,7 @@ fn find_function_in_commit( } Language::All => match file_path.split('.').last() { Some("rs") => { - let functions = rust::find_function_in_commit(commit, file_path, name)?; + let functions = rust::find_function_in_commit(&fc, name)?; Ok(File::new( file_path.to_string(), types::FileType::Rust(functions, 0), @@ -393,7 +394,7 @@ fn find_function_in_commit( } #[cfg(feature = "c_lang")] Some("c" | "h") => { - let functions = languages::c::find_function_in_commit(commit, file_path, name)?; + let functions = languages::c::find_function_in_commit(&fc, name)?; Ok(File::new( file_path.to_string(), types::FileType::C(functions, 0), @@ -401,7 +402,7 @@ fn find_function_in_commit( } Some("py") => { let functions = - languages::python::find_function_in_commit(commit, file_path, name)?; + languages::python::find_function_in_commit(&fc, name)?; Ok(File::new( file_path.to_string(), types::FileType::Python(functions, 0), diff --git a/git-function-history-lib/src/new_types.rs b/git-function-history-lib/src/new_types.rs new file mode 100644 index 00000000..e8b8347b --- /dev/null +++ b/git-function-history-lib/src/new_types.rs @@ -0,0 +1,303 @@ +// repo: struct {history: Vec} +// commit: struct {commit_hash: string commit_date: string ... files: Vec} +// filetype: enum {python(python_file), rust(rust_file), ...} all variants implement a common trait +// FileTrait trait: { +// get_file_name(&self) -> string +// get_function(&self) -> Vec +// ... +// } + +// File: struct {file_name: string functions: Vec} +// python_file: File where functions is a Vec +// rust_file: File where functions is a Vec + + +// FunctionTrait trait: { +// fmt_with_context(&self, prev option, next option) -> io::Result<()> +// ... +// } + +// functiontrait is implemented by python_function and rust_function, and is not object safe. + +use std::{fmt::{self, Display}}; + +pub fn fmt_with_context(current: T, prev: Option, next: Option, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match (prev, next) { + (Some(prev), Some(next)) => { + if prev.get_total_lines() == current.get_total_lines() && next.get_total_lines() == current.get_total_lines() { + write!(f, "{}", current.get_body())? + } else if prev.get_total_lines() == current.get_total_lines() { + write!(f, "{}", current.get_body())?; + write!(f, "{}", current.get_bottoms().join("\n"))?; + + } else if next.get_total_lines() == current.get_total_lines() { + write!(f, "{}", current.get_tops().join("\n"))?; + write!(f, "{}", current.get_body())?; + } else { + write!(f, "{}", current)?; + } + + }, + (Some(prev), None) => { + if prev.get_total_lines() == current.get_total_lines() { + write!(f, "{}", current.get_body())? + } else { + write!(f, "{}", current)?; + } + + + }, + (None, Some(next)) => { + if next.get_total_lines() == current.get_total_lines() { + write!(f, "{}", current.get_body())? + } else { + write!(f, "{}", current)?; + } + + + }, + (None, None) => { + // print the function + write!(f, "{}", current)?; + } + } + Ok(()) +} +use crate::languages::rust::RustFunction; +use crate::languages::python::PythonFunction; +pub trait FunctionTrait: fmt::Debug + fmt::Display { + fn get_tops(&self) -> Vec; + fn get_lines(&self) -> (usize, usize); + fn get_total_lines(&self) -> (usize, usize); + fn get_name(&self) -> String; + fn get_bottoms(&self) -> Vec; + fn get_body(&self) -> String; + +} + +// functiontrait is not object safe, so we can't implement it for a trait object ie box +trait FileTrait { + fn get_file_name(&self) -> String; + fn get_functions(&self) -> Vec>; +} + +impl FunctionTrait for RustFunction { + fn get_tops(&self) -> Vec { + let mut tops = Vec::new(); + match &self.block { + Some(block) => { + tops.push(block.top.clone()); + } + None => {} + } + for parent in &self.function { + tops.push(parent.top.clone()); + } + tops + } + fn get_lines(&self) -> (usize, usize) { + self.lines + } + fn get_total_lines(&self) -> (usize, usize) { + match &self.block { + Some(block) => (block.lines.0, self.lines.1), + None => { + let mut start = self.lines.0; + let mut end = self.lines.1; + for parent in &self.function { + if parent.lines.0 < start { + start = parent.lines.0; + end = parent.lines.1; + } + } + (start, end) + } + } + + } + fn get_name(&self) -> String { + self.name.clone() + } + fn get_bottoms(&self) -> Vec { + let mut bottoms = Vec::new(); + match &self.block { + Some(block) => { + bottoms.push(block.bottom.clone()); + } + None => {} + } + for parent in &self.function { + bottoms.push(parent.bottom.clone()); + } + bottoms + } + fn get_body(&self) -> String { + self.contents.clone() + } +} + +impl FunctionTrait for PythonFunction { + fn get_tops(&self) -> Vec { + let mut tops = Vec::new(); + match &self.class { + Some(block) => { + tops.push(block.top.clone()); + } + None => {} + } + for parent in &self.parent { + tops.push(parent.top.clone()); + } + tops + } + fn get_lines(&self) -> (usize, usize) { + self.lines + } + fn get_total_lines(&self) -> (usize, usize) { + match &self.class { + Some(block) => (block.lines.0, self.lines.1), + None => { + let mut start = self.lines.0; + let mut end = self.lines.1; + for parent in &self.parent { + if parent.lines.0 < start { + start = parent.lines.0; + end = parent.lines.1; + } + } + (start, end) + } + } + + } + fn get_name(&self) -> String { + self.name.clone() + } + fn get_bottoms(&self) -> Vec { + let mut bottoms = Vec::new(); + match &self.class { + Some(block) => { + bottoms.push(block.bottom.clone()); + } + None => {} + } + for parent in &self.parent { + bottoms.push(parent.bottom.clone()); + } + bottoms + } + fn get_body(&self) -> String { + self.body.clone() + } + + +} + +pub struct File { + file_name: String, + functions: Vec, +} + + + +// impl FileTrait for File { +// type FunctionType = RustFunction; +// fn get_file_name(&self) -> String { +// self.file_name.clone() +// } +// fn get_functions(&self) -> Vec { +// self.functions.clone() +// } +// } + +impl FileTrait for File { + // type FunctionType = PythonFunction; + fn get_file_name(&self) -> String { + self.file_name.clone() + } + fn get_functions(&self) -> Vec> { + self.functions.clone().iter().cloned().map(|x| Box::new(x) as Box).collect() + } +} + +impl FileTrait for File { + // type FunctionType = RustFunction; + fn get_file_name(&self) -> String { + self.file_name.clone() + } + fn get_functions(&self) -> Vec> { + self.functions.clone().iter().cloned().map(|x| Box::new(x) as Box).collect() + } +} + +impl From for Box { + fn from(f: RustFunction) -> Self { + Box::new(f) + } +} + +pub enum FileType { + Rust(File), + Python(File), +} + +impl FileTrait for FileType { + + fn get_file_name(&self) -> String { + match self { + FileType::Rust(file) => file.get_file_name(), + FileType::Python(file) => file.get_file_name(), + } + } + fn get_functions(&self) -> Vec> { + match self { + FileType::Rust(file) => file.get_functions(), + FileType::Python(file) => file.get_functions(), + } + } +} + + +#[cfg(test)] +mod tests { + use crate::languages::{rust::find_function_in_commit, python}; + + use super::*; + + #[test] + fn it_works() { + let fc = r#" + fn main() { + println!("Hello, world!"); + } + "#; + let rf = find_function_in_commit(fc, "main").unwrap(); + let f = File { + file_name: "test.rs".to_string(), + functions: rf, + }; + let fts: FileType = FileType::Rust(f); + + println!("{}", fts.get_file_name()); + println!("{:?}", fts.get_functions()); + + let fc = r#"def main(): + print("Hello, world!") + +def main2(): + print("Hello, world!") + "#; + let rf = python::find_function_in_commit(fc, "main").unwrap(); + let f = File { + file_name: "test.py".to_string(), + functions: rf, + }; + let ft: FileType = FileType::Python(f); + let mut vec = Vec::new(); + vec.push(ft); + vec.push(fts); + + + + } +} diff --git a/structure.txt b/structure.txt new file mode 100644 index 00000000..de67a210 --- /dev/null +++ b/structure.txt @@ -0,0 +1,20 @@ +repo: struct {history: Vec} +commit: struct {commit_hash: string commit_date: string ... files: Vec} +filetype: enum {python(python_file), rust(rust_file), ...} all variants implement a common trait +FileTrait trait: { + get_file_name(&self) -> string + get_function(&self) -> Vec + ... +} + +File: struct {file_name: string functions: Vec} +python_file: File where functions is a Vec +rust_file: File where functions is a Vec + + +FunctionTrait trait: { + fmt_with_context(&self, prev option, next option) -> io::Result<()> + ... +} + +functiontrait is implemented by python_function and rust_function, and is not object safe. \ No newline at end of file From a6a323d639fe1ecd8ec3034d4c1f7cd3d07dd0d6 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 9 Oct 2022 15:06:37 -0400 Subject: [PATCH 036/172] my idead actualy works just needec to cleanup add c support and documentt --- cargo-function-history/src/app/mod.rs | 16 +- cargo-function-history/src/main.rs | 20 +- function_history_backend_thread/src/types.rs | 4 +- git-function-history-gui/src/lib.rs | 32 +- git-function-history-lib/Cargo.toml | 4 +- git-function-history-lib/src/languages/c.rs | 90 +++-- git-function-history-lib/src/languages/mod.rs | 295 +++++++++------ .../src/languages/python.rs | 168 +++------ .../src/languages/rust.rs | 190 +++------- git-function-history-lib/src/lib.rs | 99 +++-- git-function-history-lib/src/new_types.rs | 303 --------------- git-function-history-lib/src/types.rs | 353 +++--------------- 12 files changed, 497 insertions(+), 1077 deletions(-) delete mode 100644 git-function-history-lib/src/new_types.rs diff --git a/cargo-function-history/src/app/mod.rs b/cargo-function-history/src/app/mod.rs index d3046337..bc0f451c 100644 --- a/cargo-function-history/src/app/mod.rs +++ b/cargo-function-history/src/app/mod.rs @@ -8,7 +8,7 @@ use function_history_backend_thread::types::{ use git_function_history::{ languages::Language, // BlockType, - FileType, + FileFilterType, Filter, }; use std::{ @@ -319,7 +319,7 @@ impl App { // with the given name Some(FullCommand::Search( name.to_string(), - FileType::None, + FileFilterType::None, Filter::None, Language::Rust, )) @@ -328,9 +328,13 @@ impl App { "relative" | "absolute" => { let file_type = match iter.next() { Some(filter) => match thing { - "relative" => FileType::Relative(filter.to_string()), - "absolute" => FileType::Absolute(filter.to_string()), - _ => FileType::None, + "relative" => { + FileFilterType::Relative(filter.to_string()) + } + "absolute" => { + FileFilterType::Absolute(filter.to_string()) + } + _ => FileFilterType::None, }, None => { self.status = @@ -449,7 +453,7 @@ impl App { }; Some(FullCommand::Search( name.to_string(), - FileType::None, + FileFilterType::None, filter, Language::Rust, )) diff --git a/cargo-function-history/src/main.rs b/cargo-function-history/src/main.rs index 286f7e1b..7bd20320 100644 --- a/cargo-function-history/src/main.rs +++ b/cargo-function-history/src/main.rs @@ -2,7 +2,7 @@ use std::{cell::RefCell, env, error::Error, process::exit, rc::Rc, sync::mpsc}; use cargo_function_history::{app::App, start_ui}; use function_history_backend_thread::types::{FullCommand, Status}; -use git_function_history::{FileType, Filter}; +use git_function_history::{FileFilterType, Filter}; use log::info; fn main() -> Result<(), Box> { @@ -46,21 +46,21 @@ fn usage() -> ! { struct Config { function_name: String, filter: Filter, - file_type: FileType, + file_type: FileFilterType, } fn parse_args() -> Config { let mut config = Config { function_name: String::new(), filter: Filter::None, - file_type: FileType::None, + file_type: FileFilterType::None, }; env::args().enumerate().skip(1).for_each(|arg| { if arg.0 == 1 { println!("{}", arg.1); match arg.1.split_once(':') { Some(string_tuple) => { - config.file_type = FileType::Relative(string_tuple.1.replace('\\', "/")); + config.file_type = FileFilterType::Relative(string_tuple.1.replace('\\', "/")); config.function_name = string_tuple.0.to_string(); } None => { @@ -74,12 +74,12 @@ fn parse_args() -> Config { } "--file-absolute" => { match &config.file_type { - FileType::None => { + FileFilterType::None => { eprintln!("Error no file name specified"); exit(1); } - FileType::Relative(path) => { - config.file_type = FileType::Absolute(path.to_string()); + FileFilterType::Relative(path) => { + config.file_type = FileFilterType::Absolute(path.to_string()); } _ => {} @@ -87,12 +87,12 @@ fn parse_args() -> Config { } "--file-relative" => { match &config.file_type { - FileType::None => { + FileFilterType::None => { eprintln!("Error no file name specified"); exit(1); } - FileType::Absolute(path) => { - config.file_type = FileType::Relative(path.to_string()); + FileFilterType::Absolute(path) => { + config.file_type = FileFilterType::Relative(path.to_string()); } _ => {} } diff --git a/function_history_backend_thread/src/types.rs b/function_history_backend_thread/src/types.rs index 28e6c492..80a44453 100644 --- a/function_history_backend_thread/src/types.rs +++ b/function_history_backend_thread/src/types.rs @@ -1,6 +1,6 @@ use std::fmt; -use git_function_history::{languages::Language, FileType, Filter, FunctionHistory}; +use git_function_history::{languages::Language, FileFilterType, Filter, FunctionHistory}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Command { @@ -117,7 +117,7 @@ impl Default for Status { pub enum FullCommand { Filter(FilterType), List(ListType), - Search(String, FileType, Filter, Language), + Search(String, FileFilterType, Filter, Language), } #[derive(Debug, Clone)] diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index 8bd9ab13..3cdda7cf 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -13,7 +13,7 @@ use function_history_backend_thread::types::{ Command, CommandResult, FilterType, FullCommand, HistoryFilterType, ListType, Status, }; use git_function_history::{ - languages::Language, types::Directions, Commit, FileType, Filter, FunctionHistory, + languages::Language, types::Directions, Commit, FileFilterType, Filter, FunctionHistory, }; // TODO: stop cloning everyting and use references instead @@ -29,7 +29,7 @@ pub struct MyEguiApp { mpsc::Receiver<(CommandResult, Status)>, ), filter: Filter, - file_type: FileType, + file_type: FileFilterType, history_filter_type: HistoryFilterType, } @@ -49,7 +49,7 @@ impl MyEguiApp { status: Status::default(), list_type: ListType::default(), channels, - file_type: FileType::None, + file_type: FileFilterType::None, filter: Filter::None, history_filter_type: HistoryFilterType::None, } @@ -476,36 +476,40 @@ impl eframe::App for MyEguiApp { }); let text = match &self.file_type { - FileType::Directory(_) => "directory", - FileType::Absolute(_) => "absolute", - FileType::Relative(_) => "relative", + FileFilterType::Directory(_) => "directory", + FileFilterType::Absolute(_) => "absolute", + FileFilterType::Relative(_) => "relative", _ => "file type", }; egui::ComboBox::from_id_source("search_file_combo_box") .selected_text(text) .show_ui(ui, |ui| { - ui.selectable_value(&mut self.file_type, FileType::None, "None"); ui.selectable_value( &mut self.file_type, - FileType::Relative(String::new()), + FileFilterType::None, + "None", + ); + ui.selectable_value( + &mut self.file_type, + FileFilterType::Relative(String::new()), "Relative", ); ui.selectable_value( &mut self.file_type, - FileType::Absolute(String::new()), + FileFilterType::Absolute(String::new()), "Absolute", ); ui.selectable_value( &mut self.file_type, - FileType::Directory(String::new()), + FileFilterType::Directory(String::new()), "Directory", ); }); match &mut self.file_type { - FileType::None => {} - FileType::Relative(dir) - | FileType::Absolute(dir) - | FileType::Directory(dir) => { + FileFilterType::None => {} + FileFilterType::Relative(dir) + | FileFilterType::Absolute(dir) + | FileFilterType::Directory(dir) => { ui.horizontal(|ui| { // set the width of the input field ui.set_min_width(4.0); diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index c2a97db1..8d1d184f 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -11,11 +11,11 @@ description = "show function history from git" [features] default = ["parallel"] parallel = ["dep:rayon"] -c-lang = [] +c_lang = [] [dependencies] chrono = "0.4.22" ra_ap_syntax = "0.0.131" rayon = { version = "1.5.1", optional = true } rustpython-parser = "0.1.2" -enum_dispatch = "0.3.8" \ No newline at end of file +enum_dispatch = "0.3.8" diff --git a/git-function-history-lib/src/languages/c.rs b/git-function-history-lib/src/languages/c.rs index 68bfb8c5..934b491f 100644 --- a/git-function-history-lib/src/languages/c.rs +++ b/git-function-history-lib/src/languages/c.rs @@ -1,6 +1,9 @@ -use std::collections::HashMap; +use std::{error::Error, fmt}; + +use crate::impl_function_trait; + +use super::FunctionTrait; -use super::FunctionResult; #[derive(Debug, Clone)] pub struct CFunction { pub(crate) name: String, @@ -11,7 +14,7 @@ pub struct CFunction { pub(crate) lines: (usize, usize), } -impl Function { +impl CFunction { pub fn new( name: String, body: String, @@ -31,31 +34,26 @@ impl Function { } } -impl super::Function for CFunction { - fn fmt_with_context( - &self, - f: &mut std::fmt::Formatter<'_>, - previous: Option<&Self>, - next: Option<&Self>, - ) -> std::fmt::Result { - todo!() - } - - fn get_metadata(&self) -> HashMap<&str, String> { - todo!() - } - fn get_lines(&self) -> (usize, usize) { - self.lines - } - - fn matches(&self, filter: &LanguageFilter) -> bool { - if let LanguageFilter::C(filt) = filter { - filt.matches(self) - } else { - false +impl fmt::Display for CFunction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.name)?; + if !self.parameters.is_empty() { + write!(f, "(")?; + for (i, param) in self.parameters.iter().enumerate() { + if i != 0 { + write!(f, ", ")?; + } + write!(f, "{}", param)?; + } + write!(f, ")")?; + } + if let Some(ret) = &self.returns { + write!(f, " -> {}", ret)?; } + Ok(()) } } + #[derive(Debug, Clone)] pub struct ParentFunction { pub(crate) name: String, @@ -66,13 +64,11 @@ pub struct ParentFunction { pub(crate) returns: Option, } -pub(crate) fn find_function_in_commit( - commit: &str, - file_path: &str, +pub(crate) fn find_function_in_commit( + file_contents: &str, name: &str, -) -> FunctionResult { - println!("Finding function {} in commit {}", name, commit); - let file_contents = crate::find_file_in_commit(commit, file_path)?; +) -> Result, Box> { + println!("Finding function {} in commit {}", name, file_contents); todo!("find_function_in_commit") } @@ -98,3 +94,35 @@ impl Filter { } } } + +impl FunctionTrait for CFunction { + fn get_total_lines(&self) -> (usize, usize) { + let mut start = self.lines.0; + let mut end = self.lines.1; + for parent in &self.parent { + if parent.lines.0 < start { + start = parent.lines.0; + end = parent.lines.1; + } + } + (start, end) + } + + fn get_tops(&self) -> Vec { + let mut tops = Vec::new(); + for parent in &self.parent { + tops.push(parent.top.clone()); + } + tops + } + + fn get_bottoms(&self) -> Vec { + let mut bottoms = Vec::new(); + for parent in &self.parent { + bottoms.push(parent.bottom.clone()); + } + bottoms + } + + impl_function_trait!(CFunction); +} diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index e4b08db3..1375cf46 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -1,4 +1,13 @@ -use std::{collections::HashMap, error::Error, fmt}; +use crate::Filter; +use std::{ + error::Error, + fmt::{self, Display}, +}; + +use self::{python::PythonFunction, rust::RustFunction}; + +#[cfg(feature = "c_lang")] +use self::c::CFunction; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Language { /// The python language @@ -51,129 +60,177 @@ pub mod c; pub mod python; pub mod rust; -pub trait Function: fmt::Debug + fmt::Display { - fn fmt_with_context( - &self, - f: &mut fmt::Formatter<'_>, - previous: Option<&Self>, - next: Option<&Self>, - ) -> fmt::Result; - fn get_metadata(&self) -> HashMap<&str, String>; - +pub trait FunctionTrait: fmt::Debug + fmt::Display { + fn get_tops(&self) -> Vec; fn get_lines(&self) -> (usize, usize); + fn get_total_lines(&self) -> (usize, usize); + fn get_name(&self) -> String; + fn get_bottoms(&self) -> Vec; + fn get_body(&self) -> String; +} + +// mace macro that generates get_lines, get_body,get_name +#[macro_export] +macro_rules! impl_function_trait { + ($name:ident) => { + fn get_lines(&self) -> (usize, usize) { + self.lines + } + + fn get_name(&self) -> String { + self.name.clone() + } + fn get_body(&self) -> String { + self.body.clone() + } + }; +} + +pub fn fmt_with_context( + current: &T, + prev: Option<&T>, + next: Option<&T>, + f: &mut fmt::Formatter<'_>, +) -> fmt::Result { + match (prev, next) { + (Some(prev), Some(next)) => { + if prev.get_total_lines() == current.get_total_lines() + && next.get_total_lines() == current.get_total_lines() + { + write!(f, "{}", current.get_body())?; + } else if prev.get_total_lines() == current.get_total_lines() { + write!(f, "{}", current.get_body())?; + write!(f, "{}", current.get_bottoms().join("\n"))?; + } else if next.get_total_lines() == current.get_total_lines() { + write!(f, "{}", current.get_tops().join("\n"))?; + write!(f, "{}", current.get_body())?; + } else { + write!(f, "{}", current)?; + } + } + (Some(prev), None) => { + if prev.get_total_lines() == current.get_total_lines() { + write!(f, "{}", current.get_body())?; + } else { + write!(f, "{}", current)?; + } + } + (None, Some(next)) => { + if next.get_total_lines() == current.get_total_lines() { + write!(f, "{}", current.get_body())?; + } else { + write!(f, "{}", current)?; + } + } + (None, None) => { + // print the function + write!(f, "{}", current)?; + } + } + Ok(()) +} - fn matches(&self, filter: &LanguageFilter) -> bool; +// functiontrait is not object safe, so we can't implement it for a trait object ie box +pub trait FileTrait: fmt::Debug + fmt::Display { + fn get_file_name(&self) -> String; + fn get_functions(&self) -> Vec>; + fn filter_by(&self, filter: &Filter) -> Result> + where + Self: Sized; + fn get_current(&self) -> Option>; } -pub type FunctionResult = Result, Box>; +// make a macro that generates the code for the different languages +macro_rules! make_file { + ($name:ident, $function:ident, $filtername:ident) => { + #[derive(Debug, Clone)] + pub struct $name { + file_name: String, + functions: Vec<$function>, + current_pos: usize, + } -// impl File { -// pub fn filter_by(&self, filter: &Filter) -> Result> { -// let mut vec = Vec::new(); -// for function in &self.functions { -// match &filter { -// Filter::FunctionInBlock(block_type) => { -// if let Some(block) = &function.block { -// if block.block_type == *block_type { -// vec.push(function.clone()); -// } -// } -// } -// Filter::FunctionInLines(start, end) => { -// if function.lines.0 >= *start && function.lines.1 <= *end { -// vec.push(function.clone()); -// } -// } -// Filter::FunctionWithParent(parent) => { -// for parents in &function.function { -// if parents.name == *parent { -// vec.push(function.clone()); -// } -// } -// } -// Filter::None => vec.push(function.clone()), -// _ => return Err("Filter not available")?, -// } -// } -// if vec.is_empty() { -// return Err("No functions found for filter")?; -// } -// Ok(Self { -// name: self.name.clone(), -// functions: vec, -// current_pos: 0, -// }) -// } -// } + impl fmt::Display for $name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for (index, func) in self.functions.iter().enumerate() { + write!( + f, + "{}", + match index { + 0 => "", + _ => "\n...\n", + }, + )?; + let previous = match index { + 0 => None, + _ => Some(&self.functions[index - 1]), + }; + let next = self.functions.get(index + 1); + crate::languages::fmt_with_context(func, previous, next, f)?; + } + Ok(()) + } + } -// impl File { -// pub fn filter_by(&self, filter: &Filter) -> Result> { -// let mut vec = Vec::new(); -// for function in &self.functions { -// match &filter { -// Filter::FunctionInBlock(block_type) => { -// if let Some(block) = &function.class { -// if block.name == *block_type.name { -// vec.push(function.clone()); -// } -// } -// } -// Filter::FunctionInLines(start, end) => { -// if function.lines.0 >= *start && function.lines.1 <= *end { -// vec.push(function.clone()); -// } -// } -// Filter::FunctionWithParent(parent) => { -// for parents in &function.parent { -// if parents.name == *parent { -// vec.push(function.clone()); -// } -// } -// } -// Filter::None => vec.push(function.clone()), -// _ => return Err("Filter not available")?, -// } -// } -// if vec.is_empty() { -// return Err("No functions found for filter")?; -// } -// Ok(Self { -// name: self.name.clone(), -// functions: vec, -// current_pos: 0, -// }) -// } -// } + impl FileTrait for $name { + fn get_file_name(&self) -> String { + self.file_name.clone() + } + fn get_functions(&self) -> Vec> { + self.functions + .clone() + .iter() + .cloned() + .map(|x| Box::new(x) as Box) + .collect() + } + fn filter_by(&self, filter: &Filter) -> Result> { + let mut filtered_functions = Vec::new(); + if let Filter::PLFilter(LanguageFilter::$filtername(_)) + | Filter::FunctionInLines(..) = filter + { + } else if let Filter::None = filter { + return Ok(self.clone()); + } else { + return Err("filter not supported for this type")?; + } + for function in &self.functions { + match filter { + Filter::FunctionInLines(start, end) => { + if function.get_lines().0 >= *start && function.get_lines().1 <= *end { + filtered_functions.push(function.clone()); + } + } + Filter::PLFilter(LanguageFilter::$filtername(filter)) => { + if filter.matches(function) { + filtered_functions.push(function.clone()); + } + } + _ => {} + } + } + Ok($name::new(self.file_name.clone(), filtered_functions)) + } + fn get_current(&self) -> Option> { + self.functions + .get(self.current_pos) + .map(|function| Box::new(function.clone()) as Box) + } + } -// impl File { -// pub fn filter_by(&self, filter: &Filter) -> Result> { -// let mut vec = Vec::new(); -// for function in &self.functions { -// match &filter { + impl $name { + pub fn new(file_name: String, functions: Vec<$function>) -> Self { + $name { + file_name, + functions, + current_pos: 0, + } + } + } + }; +} -// Filter::FunctionInLines(start, end) => { -// if function.lines.0 >= *start && function.lines.1 <= *end { -// vec.push(function.clone()); -// } -// } -// Filter::FunctionWithParent(parent) => { -// for parents in &function.parent { -// if parents.name == *parent { -// vec.push(function.clone()); -// } -// } -// } -// Filter::None => vec.push(function.clone()), -// _ => return Err("Filter not available")?, -// } -// } -// if vec.is_empty() { -// return Err("No functions found for filter")?; -// } -// Ok(Self { -// name: self.name.clone(), -// functions: vec, -// current_pos: 0, -// }) -// } -// } +make_file!(PythonFile, PythonFunction, Python); +make_file!(RustFile, RustFunction, Rust); +#[cfg(feature = "c_lang")] +make_file!(CFile, CFunction, C); diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 2ae57961..ff4e00a7 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -6,7 +6,9 @@ use rustpython_parser::{ parser, }; -use super::LanguageFilter; +use crate::impl_function_trait; + +use super::FunctionTrait; #[derive(Debug, Clone)] pub struct PythonFunction { @@ -23,9 +25,8 @@ pub struct PythonFunction { impl fmt::Display for PythonFunction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.class { - Some(ref class) => write!(f, "{}", class.top)?, - None => {} + if let Some(ref class) = self.class { + write!(f, "{}", class.top)? } for parent in &self.parent { write!(f, "{}", parent.top)?; @@ -34,112 +35,12 @@ impl fmt::Display for PythonFunction { for parent in &self.parent { write!(f, "{}", parent.bottom)?; } - match self.class { - Some(ref class) => write!(f, "{}", class.bottom), - None => Ok(()), - } + self.class + .as_ref() + .map_or(Ok(()), |class| write!(f, "{}", class.bottom)) } } -impl PythonFunction {} - -impl super::Function for PythonFunction { - fn get_lines(&self) -> (usize, usize) { - self.lines - } - fn fmt_with_context( - &self, - f: &mut std::fmt::Formatter<'_>, - previous: Option<&Self>, - next: Option<&Self>, - ) -> std::fmt::Result { - match &self.class { - Some(class) => match previous.as_ref() { - Some(previous) => { - if previous.class.is_some() { - if previous.class.as_ref().unwrap().name == class.name { - write!(f, "\n...\n")?; - } else { - write!(f, "{}", class.top)?; - } - } else { - write!(f, "{}", class.top)?; - } - } - None => { - writeln!(f, "{}", class.top)?; - } - }, - None => {} - }; - if !self.parent.is_empty() { - match previous.as_ref() { - None => { - for parent in &self.parent { - writeln!(f, "{}", parent.top)?; - } - } - Some(previous) => { - for parent in &self.parent { - if previous.parent.iter().any(|x| x.lines == parent.lines) { - } else { - write!(f, "{}\n...\n", parent.top)?; - } - } - } - } - } - write!(f, "{}", self.body)?; - if !self.parent.is_empty() { - match next.as_ref() { - None => { - for parent in &self.parent { - writeln!(f, "{}", parent.bottom)?; - } - } - Some(next) => { - for parent in &self.parent { - if next.parent.iter().any(|x| x.lines == parent.lines) { - } else { - write!(f, "\n...\n{}", parent.bottom)?; - } - } - } - } - } - match &self.class { - Some(class) => match next.as_ref() { - Some(next) => { - if next.class.is_some() { - if next.class.as_ref().unwrap().name == class.name { - write!(f, "\n...\n")?; - } else { - write!(f, "{}", class.bottom)?; - } - } else { - write!(f, "{}", class.bottom)?; - } - } - None => { - writeln!(f, "{}", class.bottom)?; - } - }, - None => {} - }; - Ok(()) - } - - fn get_metadata(&self) -> HashMap<&str, String> { - todo!() - } - fn matches(&self, filter: &LanguageFilter) -> bool { - if let LanguageFilter::Python(filt) = filter { - filt.matches(self) - } else { - false - } - } -} #[derive(Debug, Clone)] pub struct Params { args: Vec, @@ -169,11 +70,10 @@ pub struct ParentFunction { pub(crate) fn find_function_in_commit( file_contents: &str, - + name: &str, ) -> Result, Box> { - - let ast = parser::parse_program(&file_contents)?; + let ast = parser::parse_program(file_contents)?; let mut functions = vec![]; let mut last = None; for stmt in ast.statements { @@ -405,3 +305,51 @@ impl Filter { } } } + +impl FunctionTrait for PythonFunction { + fn get_tops(&self) -> Vec { + let mut tops = Vec::new(); + match &self.class { + Some(block) => { + tops.push(block.top.clone()); + } + None => {} + } + for parent in &self.parent { + tops.push(parent.top.clone()); + } + tops + } + + fn get_total_lines(&self) -> (usize, usize) { + match &self.class { + Some(block) => (block.lines.0, self.lines.1), + None => { + let mut start = self.lines.0; + let mut end = self.lines.1; + for parent in &self.parent { + if parent.lines.0 < start { + start = parent.lines.0; + end = parent.lines.1; + } + } + (start, end) + } + } + } + + fn get_bottoms(&self) -> Vec { + let mut bottoms = Vec::new(); + match &self.class { + Some(block) => { + bottoms.push(block.bottom.clone()); + } + None => {} + } + for parent in &self.parent { + bottoms.push(parent.bottom.clone()); + } + bottoms + } + impl_function_trait!(PythonFunction); +} diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index b18fd3ef..1c1ae73a 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -5,14 +5,16 @@ use ra_ap_syntax::{ AstNode, SourceFile, SyntaxKind, }; -use super::LanguageFilter; +use crate::impl_function_trait; + +use super::FunctionTrait; /// This holds the information about a single function each commit will have multiple of these. #[derive(Debug, Clone)] pub struct RustFunction { pub(crate) name: String, /// The actual code of the function - pub(crate) contents: String, + pub(crate) body: String, /// is the function in a block ie `impl` `trait` etc pub(crate) block: Option, /// optional parent functions @@ -33,123 +35,6 @@ pub struct RustFunction { pub(crate) doc_comments: Vec, } -impl super::Function for RustFunction { - fn matches(&self, filter: &LanguageFilter) -> bool { - if let LanguageFilter::Rust(filt) = filter { - filt.matches(self) - } else { - false - } - } - /// This is a formater almost like the fmt you use for println!, but it takes a previous and next function. - /// This is usefull for printing `CommitHistory` or a vector of functions, because if you use plain old fmt, you can get repeated lines impls, and parent function in your output. - fn fmt_with_context( - &self, - f: &mut fmt::Formatter<'_>, - previous: Option<&Self>, - next: Option<&Self>, - ) -> fmt::Result { - match &self.block { - None => {} - Some(block) => match previous.as_ref() { - None => write!(f, "{}\n...\n", block.top)?, - Some(previous_function) => match &previous_function.block { - None => write!(f, "{}\n...\n", block.top)?, - // TODO: chek for different blocks - Some(previous_block) => { - if previous_block.lines == block.lines { - } else { - write!(f, "{}\n...\n", block.top)?; - } - } - }, - }, - }; - if !self.function.is_empty() { - for i in &self.function { - match previous.as_ref() { - None => write!(f, "{}\n...\n", i.top)?, - Some(previous_function) => { - if previous_function - .function - .iter() - .any(|x| x.lines == i.lines) - { - } else { - write!(f, "{}\n...\n", i.top)?; - } - } - }; - } - } - - write!(f, "{}", self.contents)?; - if !self.function.is_empty() { - for i in &self.function { - match next.as_ref() { - None => write!(f, "\n...{}", i.bottom)?, - Some(next_function) => { - if next_function.function.iter().any(|x| x.lines == i.lines) { - } else { - write!(f, "\n...{}", i.bottom)?; - } - } - }; - } - } - match &self.block { - None => {} - Some(block) => match next.as_ref() { - None => write!(f, "\n...{}", block.bottom)?, - Some(next_function) => match &next_function.block { - None => write!(f, "\n...{}", block.bottom)?, - Some(next_block) => { - if next_block.lines == block.lines { - } else { - write!(f, "\n...{}", block.bottom)?; - } - } - }, - }, - }; - Ok(()) - } - - /// get metadata like line number, number of parent function etc. - fn get_metadata(&self) -> HashMap<&str, String> { - let mut map = HashMap::new(); - map.insert("name", self.name.clone()); - map.insert("lines", format!("{:?}", self.lines)); - map.insert("contents", self.contents.clone()); - if let Some(block) = &self.block { - map.insert("block", format!("{}", block.block_type)); - } - map.insert("generics", self.generics.join(",")); - map.insert( - "arguments", - self.arguments - .iter() - .map(|(k, v)| format!("{}: {}", k, v)) - .collect::>() - .join(","), - ); - map.insert("lifetime generics", self.lifetime.join(",")); - map.insert("attributes", self.attributes.join(",")); - map.insert("doc comments", self.doc_comments.join(",")); - match &self.return_type { - None => {} - Some(return_type) => { - map.insert("return type", return_type.clone()); - } - }; - map - } - - fn get_lines(&self) -> (usize, usize) { - self.lines - } -} - impl RustFunction { /// get the parent functions pub fn get_parent_function(&self) -> Vec { @@ -171,7 +56,7 @@ impl fmt::Display for RustFunction { for i in &self.function { write!(f, "{}\n...\n", i.top)?; } - write!(f, "{}", self.contents)?; + write!(f, "{}", self.body)?; for i in &self.function { write!(f, "\n...\n{}", i.bottom)?; } @@ -323,7 +208,7 @@ pub(crate) fn find_function_in_commit( name: &str, ) -> Result, Box> { let mut functions = Vec::new(); - get_function_asts(name, &file_contents, &mut functions); + get_function_asts(name, file_contents, &mut functions); let mut starts = file_contents .match_indices('\n') .map(|x| x.0) @@ -336,7 +221,7 @@ pub(crate) fn find_function_in_commit( .collect::>(); let mut hist = Vec::new(); for f in &functions { - let stuff = get_stuff(f, &file_contents, &map); + let stuff = get_stuff(f, file_contents, &map); let generics = get_genrerics_and_lifetime(f); let mut parent = f.syntax().parent(); let mut parent_fn: Vec = Vec::new(); @@ -349,7 +234,7 @@ pub(crate) fn find_function_in_commit( || { if let Some(block) = ast::Impl::cast(p.clone()) { let attr = get_doc_comments_and_attrs(&block); - let stuff = get_stuff(&block, &file_contents, &map); + let stuff = get_stuff(&block, file_contents, &map); let generics = get_genrerics_and_lifetime(&block); parent_block = Some(Block { name: block.self_ty().map(|ty| ty.to_string()), @@ -364,7 +249,7 @@ pub(crate) fn find_function_in_commit( }); } else if let Some(block) = ast::Trait::cast(p.clone()) { let attr = get_doc_comments_and_attrs(&block); - let stuff = get_stuff(&block, &file_contents, &map); + let stuff = get_stuff(&block, file_contents, &map); let generics = get_genrerics_and_lifetime(&block); parent_block = Some(Block { name: block.name().map(|ty| ty.to_string()), @@ -379,7 +264,7 @@ pub(crate) fn find_function_in_commit( }); } else if let Some(block) = ast::ExternBlock::cast(p.clone()) { let attr = get_doc_comments_and_attrs(&block); - let stuff = get_stuff(&block, &file_contents, &map); + let stuff = get_stuff(&block, file_contents, &map); parent_block = Some(Block { name: block.abi().map(|ty| ty.to_string()), lifetime: Vec::new(), @@ -394,7 +279,7 @@ pub(crate) fn find_function_in_commit( } }, |function| { - let stuff = get_stuff(&function, &file_contents, &map); + let stuff = get_stuff(&function, file_contents, &map); let generics = get_genrerics_and_lifetime(&function); let attr = get_doc_comments_and_attrs(&function); parent_fn.push(FunctionBlock { @@ -437,10 +322,10 @@ pub(crate) fn find_function_in_commit( format!("{}: {}\n", start, l,) }) .collect(); - let contents = contents.trim_end().to_string(); + let body = contents.trim_end().to_string(); let function = RustFunction { name: f.name().unwrap().to_string(), - contents, + body, block: parent_block, function: parent_fn, return_type: f.ret_type().map(|ty| ty.to_string()), @@ -619,3 +504,52 @@ impl Filter { } } } + +impl FunctionTrait for RustFunction { + fn get_tops(&self) -> Vec { + let mut tops = Vec::new(); + match &self.block { + Some(block) => { + tops.push(block.top.clone()); + } + None => {} + } + for parent in &self.function { + tops.push(parent.top.clone()); + } + tops + } + + fn get_total_lines(&self) -> (usize, usize) { + match &self.block { + Some(block) => (block.lines.0, self.lines.1), + None => { + let mut start = self.lines.0; + let mut end = self.lines.1; + for parent in &self.function { + if parent.lines.0 < start { + start = parent.lines.0; + end = parent.lines.1; + } + } + (start, end) + } + } + } + + fn get_bottoms(&self) -> Vec { + let mut bottoms = Vec::new(); + match &self.block { + Some(block) => { + bottoms.push(block.bottom.clone()); + } + None => {} + } + for parent in &self.function { + bottoms.push(parent.bottom.clone()); + } + bottoms + } + + impl_function_trait!(RustFunction); +} diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 2f2a3e85..62803838 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -13,23 +13,29 @@ clippy::missing_errors_doc, clippy::return_self_not_must_use )] -pub mod new_types; pub mod languages; + /// Different types that can extracted from the result of `get_function_history`. pub mod types; use languages::{rust, LanguageFilter}; + +use languages::{PythonFile, RustFile}; #[cfg(feature = "parallel")] use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; +pub use types::FileType; + +#[cfg(feature = "c_lang")] +use languages::CFile; use std::{error::Error, process::Command}; -pub use types::{Commit, File, FunctionHistory}; +pub use types::{Commit, FunctionHistory}; use crate::languages::Language; /// Different filetypes that can be used to ease the process of finding functions using `get_function_history`. #[derive(Debug, Clone, PartialEq, Eq)] -pub enum FileType { +pub enum FileFilterType { /// When you have a absolute path to a file. Absolute(String), /// When you have a relative path to a file and or want to find look in all files match a name. @@ -103,7 +109,7 @@ pub enum Filter { // TODO: split this function into smaller functions pub fn get_function_history( name: &str, - file: &FileType, + file: &FileFilterType, filter: &Filter, langs: &languages::Language, ) -> Result> { @@ -183,7 +189,7 @@ pub fn get_function_history( let mut file_history = FunctionHistory::new(String::from(name), Vec::new()); let err = "no history found".to_string(); // check if file is a rust file - if let FileType::Absolute(path) | FileType::Relative(path) = &file { + if let FileFilterType::Absolute(path) | FileFilterType::Relative(path) = &file { match langs { #[cfg(feature = "c_lang")] Language::C => { @@ -218,10 +224,10 @@ pub fn get_function_history( let t = commits.iter(); file_history.commit_history = t .filter_map(|commit| match &file { - FileType::Absolute(_) - | FileType::Relative(_) - | FileType::None - | FileType::Directory(_) => { + FileFilterType::Absolute(_) + | FileFilterType::Relative(_) + | FileFilterType::None + | FileFilterType::Directory(_) => { match find_function_in_commit_with_filetype(commit.0, name, file, *langs) { Ok(contents) => Some(Commit::new( commit.0.to_string(), @@ -279,9 +285,9 @@ fn find_file_in_commit(commit: &str, file_path: &str) -> Result Result, Box> { +) -> Result, Box> { // get a list of all the files in the repository let mut files = Vec::new(); let command = Command::new("git") @@ -293,22 +299,22 @@ fn find_function_in_commit_with_filetype( let file_list = String::from_utf8_lossy(&command.stdout).to_string(); for file in file_list.split('\n') { match filetype { - FileType::Relative(ref path) => { + FileFilterType::Relative(ref path) => { if file.ends_with(path) { files.push(file); } } - FileType::Absolute(ref path) => { + FileFilterType::Absolute(ref path) => { if file == path { files.push(file); } } - FileType::Directory(ref path) => { + FileFilterType::Directory(ref path) => { if path.contains(path) { files.push(file); } } - FileType::None => { + FileFilterType::None => { match langs { #[cfg(feature = "c_lang")] Language::C => { @@ -345,7 +351,7 @@ fn find_function_in_commit_with_filetype( let t = files.par_iter(); #[cfg(not(feature = "parellel"))] let t = files.iter(); - let returns: Vec = t + let returns: Vec = t .filter_map(|file| find_function_in_commit(commit, file, name, langs).ok()) .collect(); if returns.is_empty() { @@ -359,54 +365,41 @@ fn find_function_in_commit( file_path: &str, name: &str, langs: Language, -) -> Result> { +) -> Result> { let fc = find_file_in_commit(commit, file_path)?; match langs { Language::Rust => { let functions = rust::find_function_in_commit(&fc, name)?; - Ok(File::new( - file_path.to_string(), - types::FileType::Rust(functions, 0), - )) + Ok(FileType::Rust(RustFile::new(name.to_string(), functions))) } #[cfg(feature = "c_lang")] Language::C => { let functions = languages::c::find_function_in_commit(&fc, name)?; - Ok(File::new( - file_path.to_string(), - types::FileType::C(functions, 0), - )) + Ok(FileType::C(CFile::new(name.to_string(), functions))) } Language::Python => { let functions = languages::python::find_function_in_commit(&fc, name)?; - Ok(File::new( - file_path.to_string(), - types::FileType::Python(functions, 0), - )) + Ok(FileType::Python(PythonFile::new( + name.to_string(), + functions, + ))) } Language::All => match file_path.split('.').last() { Some("rs") => { let functions = rust::find_function_in_commit(&fc, name)?; - Ok(File::new( - file_path.to_string(), - types::FileType::Rust(functions, 0), - )) + Ok(FileType::Rust(RustFile::new(name.to_string(), functions))) } #[cfg(feature = "c_lang")] Some("c" | "h") => { let functions = languages::c::find_function_in_commit(&fc, name)?; - Ok(File::new( - file_path.to_string(), - types::FileType::C(functions, 0), - )) + Ok(FileType::C(CFile::new(name.to_string(), functions))) } Some("py") => { - let functions = - languages::python::find_function_in_commit(&fc, name)?; - Ok(File::new( - file_path.to_string(), - types::FileType::Python(functions, 0), - )) + let functions = languages::python::find_function_in_commit(&fc, name)?; + Ok(FileType::Python(PythonFile::new( + name.to_string(), + functions, + ))) } _ => Err("unknown file type")?, }, @@ -430,13 +423,15 @@ impl UnwrapToError for Option { mod tests { use chrono::Utc; + use crate::languages::FileTrait; + use super::*; #[test] fn found_function() { let now = Utc::now(); let output = get_function_history( "empty_test", - &FileType::Relative("src/test_functions.rs".to_string()), + &FileFilterType::Relative("src/test_functions.rs".to_string()), &Filter::None, &languages::Language::Rust, ); @@ -454,7 +449,7 @@ mod tests { fn git_installed() { let output = get_function_history( "empty_test", - &FileType::Absolute("src/test_functions.rs".to_string()), + &FileFilterType::Absolute("src/test_functions.rs".to_string()), &Filter::None, &languages::Language::Rust, ); @@ -468,7 +463,7 @@ mod tests { fn not_found() { let output = get_function_history( "Not_a_function", - &FileType::Absolute("src/test_functions.rs".to_string()), + &FileFilterType::Absolute("src/test_functions.rs".to_string()), &Filter::None, &languages::Language::Rust, ); @@ -483,7 +478,7 @@ mod tests { fn not_rust_file() { let output = get_function_history( "empty_test", - &FileType::Absolute("src/test_functions.txt".to_string()), + &FileFilterType::Absolute("src/test_functions.txt".to_string()), &Filter::None, &languages::Language::Rust, ); @@ -495,7 +490,7 @@ mod tests { let now = Utc::now(); let output = get_function_history( "empty_test", - &FileType::None, + &FileFilterType::None, &Filter::DateRange( "27 Sep 2022 11:27:23 -0400".to_owned(), "04 Oct 2022 23:45:52 +0000".to_owned(), @@ -518,7 +513,7 @@ mod tests { let now = Utc::now(); let output = get_function_history( "empty_test", - &FileType::None, + &FileFilterType::None, &Filter::None, &languages::Language::Rust, ); @@ -538,7 +533,7 @@ mod tests { let now = Utc::now(); let output = get_function_history( "empty_test", - &FileType::Relative("src/test_functions.py".to_string()), + &FileFilterType::Relative("src/test_functions.py".to_string()), &Filter::DateRange( "03 Oct 2022 11:27:23 -0400".to_owned(), "04 Oct 2022 23:45:52 +0000".to_owned(), @@ -557,7 +552,7 @@ mod tests { let output = output.unwrap(); let commit = output.get_commit(); let file = commit.get_file(); - let functions = file.get_functions(); + let _functions = file.get_functions(); } #[test] @@ -566,7 +561,7 @@ mod tests { let now = Utc::now(); let output = get_function_history( "empty_test", - &FileType::Relative("src/test_functions.c".to_string()), + &FileFilterType::Relative("src/test_functions.c".to_string()), &Filter::DateRange( "03 Oct 2022 11:27:23 -0400".to_owned(), "05 Oct 2022 23:45:52 +0000".to_owned(), diff --git a/git-function-history-lib/src/new_types.rs b/git-function-history-lib/src/new_types.rs deleted file mode 100644 index e8b8347b..00000000 --- a/git-function-history-lib/src/new_types.rs +++ /dev/null @@ -1,303 +0,0 @@ -// repo: struct {history: Vec} -// commit: struct {commit_hash: string commit_date: string ... files: Vec} -// filetype: enum {python(python_file), rust(rust_file), ...} all variants implement a common trait -// FileTrait trait: { -// get_file_name(&self) -> string -// get_function(&self) -> Vec -// ... -// } - -// File: struct {file_name: string functions: Vec} -// python_file: File where functions is a Vec -// rust_file: File where functions is a Vec - - -// FunctionTrait trait: { -// fmt_with_context(&self, prev option, next option) -> io::Result<()> -// ... -// } - -// functiontrait is implemented by python_function and rust_function, and is not object safe. - -use std::{fmt::{self, Display}}; - -pub fn fmt_with_context(current: T, prev: Option, next: Option, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match (prev, next) { - (Some(prev), Some(next)) => { - if prev.get_total_lines() == current.get_total_lines() && next.get_total_lines() == current.get_total_lines() { - write!(f, "{}", current.get_body())? - } else if prev.get_total_lines() == current.get_total_lines() { - write!(f, "{}", current.get_body())?; - write!(f, "{}", current.get_bottoms().join("\n"))?; - - } else if next.get_total_lines() == current.get_total_lines() { - write!(f, "{}", current.get_tops().join("\n"))?; - write!(f, "{}", current.get_body())?; - } else { - write!(f, "{}", current)?; - } - - }, - (Some(prev), None) => { - if prev.get_total_lines() == current.get_total_lines() { - write!(f, "{}", current.get_body())? - } else { - write!(f, "{}", current)?; - } - - - }, - (None, Some(next)) => { - if next.get_total_lines() == current.get_total_lines() { - write!(f, "{}", current.get_body())? - } else { - write!(f, "{}", current)?; - } - - - }, - (None, None) => { - // print the function - write!(f, "{}", current)?; - } - } - Ok(()) -} -use crate::languages::rust::RustFunction; -use crate::languages::python::PythonFunction; -pub trait FunctionTrait: fmt::Debug + fmt::Display { - fn get_tops(&self) -> Vec; - fn get_lines(&self) -> (usize, usize); - fn get_total_lines(&self) -> (usize, usize); - fn get_name(&self) -> String; - fn get_bottoms(&self) -> Vec; - fn get_body(&self) -> String; - -} - -// functiontrait is not object safe, so we can't implement it for a trait object ie box -trait FileTrait { - fn get_file_name(&self) -> String; - fn get_functions(&self) -> Vec>; -} - -impl FunctionTrait for RustFunction { - fn get_tops(&self) -> Vec { - let mut tops = Vec::new(); - match &self.block { - Some(block) => { - tops.push(block.top.clone()); - } - None => {} - } - for parent in &self.function { - tops.push(parent.top.clone()); - } - tops - } - fn get_lines(&self) -> (usize, usize) { - self.lines - } - fn get_total_lines(&self) -> (usize, usize) { - match &self.block { - Some(block) => (block.lines.0, self.lines.1), - None => { - let mut start = self.lines.0; - let mut end = self.lines.1; - for parent in &self.function { - if parent.lines.0 < start { - start = parent.lines.0; - end = parent.lines.1; - } - } - (start, end) - } - } - - } - fn get_name(&self) -> String { - self.name.clone() - } - fn get_bottoms(&self) -> Vec { - let mut bottoms = Vec::new(); - match &self.block { - Some(block) => { - bottoms.push(block.bottom.clone()); - } - None => {} - } - for parent in &self.function { - bottoms.push(parent.bottom.clone()); - } - bottoms - } - fn get_body(&self) -> String { - self.contents.clone() - } -} - -impl FunctionTrait for PythonFunction { - fn get_tops(&self) -> Vec { - let mut tops = Vec::new(); - match &self.class { - Some(block) => { - tops.push(block.top.clone()); - } - None => {} - } - for parent in &self.parent { - tops.push(parent.top.clone()); - } - tops - } - fn get_lines(&self) -> (usize, usize) { - self.lines - } - fn get_total_lines(&self) -> (usize, usize) { - match &self.class { - Some(block) => (block.lines.0, self.lines.1), - None => { - let mut start = self.lines.0; - let mut end = self.lines.1; - for parent in &self.parent { - if parent.lines.0 < start { - start = parent.lines.0; - end = parent.lines.1; - } - } - (start, end) - } - } - - } - fn get_name(&self) -> String { - self.name.clone() - } - fn get_bottoms(&self) -> Vec { - let mut bottoms = Vec::new(); - match &self.class { - Some(block) => { - bottoms.push(block.bottom.clone()); - } - None => {} - } - for parent in &self.parent { - bottoms.push(parent.bottom.clone()); - } - bottoms - } - fn get_body(&self) -> String { - self.body.clone() - } - - -} - -pub struct File { - file_name: String, - functions: Vec, -} - - - -// impl FileTrait for File { -// type FunctionType = RustFunction; -// fn get_file_name(&self) -> String { -// self.file_name.clone() -// } -// fn get_functions(&self) -> Vec { -// self.functions.clone() -// } -// } - -impl FileTrait for File { - // type FunctionType = PythonFunction; - fn get_file_name(&self) -> String { - self.file_name.clone() - } - fn get_functions(&self) -> Vec> { - self.functions.clone().iter().cloned().map(|x| Box::new(x) as Box).collect() - } -} - -impl FileTrait for File { - // type FunctionType = RustFunction; - fn get_file_name(&self) -> String { - self.file_name.clone() - } - fn get_functions(&self) -> Vec> { - self.functions.clone().iter().cloned().map(|x| Box::new(x) as Box).collect() - } -} - -impl From for Box { - fn from(f: RustFunction) -> Self { - Box::new(f) - } -} - -pub enum FileType { - Rust(File), - Python(File), -} - -impl FileTrait for FileType { - - fn get_file_name(&self) -> String { - match self { - FileType::Rust(file) => file.get_file_name(), - FileType::Python(file) => file.get_file_name(), - } - } - fn get_functions(&self) -> Vec> { - match self { - FileType::Rust(file) => file.get_functions(), - FileType::Python(file) => file.get_functions(), - } - } -} - - -#[cfg(test)] -mod tests { - use crate::languages::{rust::find_function_in_commit, python}; - - use super::*; - - #[test] - fn it_works() { - let fc = r#" - fn main() { - println!("Hello, world!"); - } - "#; - let rf = find_function_in_commit(fc, "main").unwrap(); - let f = File { - file_name: "test.rs".to_string(), - functions: rf, - }; - let fts: FileType = FileType::Rust(f); - - println!("{}", fts.get_file_name()); - println!("{:?}", fts.get_functions()); - - let fc = r#"def main(): - print("Hello, world!") - -def main2(): - print("Hello, world!") - "#; - let rf = python::find_function_in_commit(fc, "main").unwrap(); - let f = File { - file_name: "test.py".to_string(), - functions: rf, - }; - let ft: FileType = FileType::Python(f); - let mut vec = Vec::new(); - vec.push(ft); - vec.push(fts); - - - - } -} diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index cd707ed1..323d6937 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -2,336 +2,89 @@ use chrono::{DateTime, FixedOffset}; use rayon::prelude::IntoParallelRefIterator; #[cfg(feature = "parallel")] use rayon::prelude::ParallelIterator; -use std::{collections::HashMap, error::Error, fmt::{self, Formatter, Display}}; +use std::{ + collections::HashMap, + error::Error, + fmt::{self, Display, Formatter}, +}; use crate::{ - languages::{python::{self, PythonFunction}, rust::{self, RustFunction}, Function, LanguageFilter}, + languages::{FileTrait, FunctionTrait, PythonFile, RustFile}, Filter, }; #[cfg(feature = "c_lang")] -use crate::languages::c; +use crate::languages::CFile; -/// This is used to store each individual file in a commit and the associated functions in that file. #[derive(Debug, Clone)] -pub struct File { - /// The name of the file - pub(crate) name: String, - pub(crate) functions: FileType, - pub(crate) current_pos: usize, +pub enum FileType { + Rust(RustFile), + Python(PythonFile), + #[cfg(feature = "c_lang")] + C(CFile), } -impl File { - /// Create a new file with the given name and functions - pub const fn new(name: String, functions: FileType) -> Self { - Self { - name, - functions, - current_pos: 0, - } - } - - /// This is used to get the functions in the file - pub const fn get_functions(&self) -> &FileType { - &self.functions - } - - /// This is used to get the functions in the file (mutable) - pub fn get_functions_mut(&mut self) -> &mut FileType { - &mut self.functions - } - - pub fn filter_by(&self, filter: &Filter) -> Result> { - match filter { - Filter::FunctionInLines(..) | Filter::PLFilter(_) => {} - Filter::None => return Ok(self.clone()), - _ => return Err("Filter not available")?, - } - let mut new_file = self.clone(); - new_file.functions = match &self.functions { - FileType::Rust(functions, _) => { - let mut vec = Vec::new(); - for function in functions { - match &filter { - Filter::FunctionInLines(start, end) => { - if function.lines.0 >= *start && function.lines.1 <= *end { - vec.push(function.clone()); - } - } - Filter::PLFilter(LanguageFilter::Rust(filter)) => { - if filter.matches(function) { - vec.push(function.clone()); - } - } - _ => return Err("Filter not available")?, - } - } - if vec.is_empty() { - return Err("No functions found for filter")?; - } - FileType::Rust(vec, 0) - } - - FileType::Python(functions, _) => { - let mut vec = Vec::new(); - for function in functions { - match &filter { - Filter::FunctionInLines(start, end) => { - if function.lines.0 >= *start && function.lines.1 <= *end { - vec.push(function.clone()); - } - } - Filter::PLFilter(LanguageFilter::Python(filter)) => { - if filter.matches(function) { - vec.push(function.clone()); - } - } - _ => return Err("Filter not available")?, - } - } - if vec.is_empty() { - return Err("No functions found for filter")?; - } - FileType::Python(vec, 0) - } - #[cfg(feature = "c_lang")] - FileType::C(functions, _) => { - let mut vec = Vec::new(); - for function in functions { - match &filter { - Filter::FunctionInLines(start, end) => { - if function.lines.0 >= *start && function.lines.1 <= *end { - vec.push(function.clone()); - } - } - Filter::PLFilter(LanguageFilter::C(filter)) => { - if filter.matches(function) { - vec.push(function.clone()); - } - } - _ => return Err("Filter not available")?, - } - } - if vec.is_empty() { - return Err("No functions found for filter")?; - } - FileType::C(vec, 0) - } - }; - match &new_file.functions { +impl FileTrait for FileType { + fn get_file_name(&self) -> String { + match self { + Self::Rust(file) => file.get_file_name(), + Self::Python(file) => file.get_file_name(), #[cfg(feature = "c_lang")] - FileType::C(functions, _) => { - if functions.is_empty() { - return Err("No functions found for filter")?; - } - } - FileType::Python(functions, _) => { - if functions.is_empty() { - return Err("No functions found for filter")?; - } - } - FileType::Rust(functions, _) => { - if functions.is_empty() { - return Err("No functions found for filter")?; - } - } + FileType::C(file) => file.get_file_name(), } - Ok(new_file) - } - - /// This is will get the current function in the file - pub fn get_current_function(&self) -> Option { - self.functions.get(self.current_pos) - } -} - -impl Display for File { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - // write!(f, "{}", self.name) - match &self.functions { - FileType::Python(python, _) => { - for (i, function) in python.iter().enumerate() { - write!( - f, - "{}", - match i { - 0 => "", - _ => "\n...\n", - }, - )?; - let previous = match i { - 0 => None, - _ => python.get(i - 1), - }; - let next = python.get(i + 1); - function.fmt_with_context(f, previous,next); - } - } - FileType::Rust(rust, _) => { - for (i, function) in rust.iter().enumerate() { - write!( - f, - "{}", - match i { - 0 => "", - _ => "\n...\n", - }, - )?; - let previous = match i { - 0 => None, - _ => rust.get(i - 1), - }; - let next = rust.get(i + 1); - function.fmt_with_context(f, previous,next); - } - } - #[cfg(feature = "c_lang")] - FileType::C(c, _) => { - for (i, function) in c.iter().enumerate() { - write!( - f, - "{}", - match i { - 0 => "", - _ => "\n...\n", - }, - )?; - let previous = match i { - 0 => None, - _ => c.get(i - 1), - }; - let next = c.get(i + 1); - function.fmt_with_context(f, previous,next); - } - } - }; - Ok(()) } -} - -pub enum FunctionType { - Python(python::PythonFunction), - Rust(rust::RustFunction), - #[cfg(feature = "c_lang")] - C(c::Function), -} - -impl FunctionType { - pub const fn get_lines(&self) -> (usize, usize) { + fn get_functions(&self) -> Vec> { match self { - Self::Python(python) => python.lines, - Self::Rust(rust) => rust.lines, + Self::Rust(file) => file.get_functions(), + Self::Python(file) => file.get_functions(), #[cfg(feature = "c_lang")] - Self::C(c) => c.lines, + FileType::C(file) => file.get_functions(), } } -} - -impl Iterator for File { - type Item = FunctionType; - - fn next(&mut self) -> Option { - let current = self.current_pos; - self.current_pos += 1; - match &self.functions { - FileType::Python(python, _) => { - python.get(current).map(|f| FunctionType::Python(f.clone())) + fn filter_by(&self, filter: &Filter) -> Result> { + match self { + Self::Rust(file) => { + let filtered = file.filter_by(filter)?; + Ok(Self::Rust(filtered)) + } + Self::Python(file) => { + let filtered = file.filter_by(filter)?; + Ok(Self::Python(filtered)) } - FileType::Rust(rust, _) => rust.get(current).map(|f| FunctionType::Rust(f.clone())), #[cfg(feature = "c_lang")] - FileType::C(c, _) => c.get(current).map(|f| FunctionType::C(f.clone())), + FileType::C(file) => { + let filtered = file.filter_by(filter)?; + Ok(FileType::C(filtered)) + } } } -} - -#[derive(Debug, Clone)] -pub enum FileType { - /// The python language - Python(Vec, usize), - /// The rust language - Rust(Vec, usize), - #[cfg(feature = "c_lang")] - /// c language - C(Vec, usize), -} - -impl Iterator for FileType { - type Item = FunctionType; - fn next(&mut self) -> Option { + fn get_current(&self) -> Option> { match self { - Self::Python(python, pos) => python.get(*pos).map(|f| { - *pos += 1; - FunctionType::Python(f.clone()) - }), - Self::Rust(rust, pos) => rust.get(*pos).map(|f| { - *pos += 1; - FunctionType::Rust(f.clone()) - }), + Self::Rust(file) => file.get_current(), + Self::Python(file) => file.get_current(), #[cfg(feature = "c_lang")] - Self::C(c, pos) => c.get(*pos).map(|f| { - *pos += 1; - FunctionType::C(f.clone()) - }), + FileType::C(file) => file.get_current(), } } } -impl FileType { - pub fn get(&self, index: usize) -> Option { +impl fmt::Display for FileType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Rust(rust, _) => rust - .get(index) - .map(|function| FunctionType::Rust(function.clone())), + Self::Rust(file) => write!(f, "{}", file), + Self::Python(file) => write!(f, "{}", file), #[cfg(feature = "c_lang")] - Self::C(c, _) => c - .get(index) - .map(|function| FunctionType::C(function.clone())), - Self::Python(python, _) => python - .get(index) - .map(|function| FunctionType::Python(function.clone())), - } - } - #[cfg(feature = "c_lang")] - pub fn get_current< - T: Clone + From + From + From, - >( - &self, - ) -> Vec { - match self { - Self::Python(python, _pos) => python - .iter() - .map(|function| T::from(function.clone())) - .collect(), - Self::Rust(rust, _pos) => rust - .iter() - .map(|function| T::from(function.clone())) - .collect(), - Self::C(c, _pos) => c.iter().map(|function| T::from(function.clone())).collect(), - } - } - - #[cfg(not(feature = "c_lang"))] - pub fn get_current + From>(&self) -> Vec { - match self { - Self::Python(python, _pos) => python - .iter() - .map(|function| T::from(function.clone())) - .collect(), - Self::Rust(rust, _pos) => rust - .iter() - .map(|function| T::from(function.clone())) - .collect(), + FileType::C(file) => write!(f, "{}", file), } } } - /// This holds information like date and commit `commit_hash` and also the list of function found in the commit. #[derive(Debug, Clone)] pub struct Commit { commit_hash: String, - files: Vec, + files: Vec, pub(crate) date: DateTime, current_iter_pos: usize, current_pos: usize, @@ -344,7 +97,7 @@ impl Commit { /// Create a new `Commit` with the given `commit_hash`, functions, and date. pub fn new( commit_hash: String, - files: Vec, + files: Vec, date: &str, author: String, email: String, @@ -386,18 +139,18 @@ impl Commit { map.insert("date".to_string(), self.date.to_rfc2822()); map.insert( "file".to_string(), - self.files[self.current_pos].name.clone(), + self.files[self.current_pos].get_file_name(), ); map } /// returns the current file - pub fn get_file(&self) -> &File { + pub fn get_file(&self) -> &FileType { &self.files[self.current_pos] } /// returns the current file (mutable) - pub fn get_file_mut(&mut self) -> &mut File { + pub fn get_file_mut(&mut self) -> &mut FileType { &mut self.files[self.current_pos] } @@ -432,9 +185,9 @@ impl Commit { let t = self.files.iter(); let vec: Vec<_> = t .filter(|f| match filter { - Filter::FileAbsolute(file) => f.name == *file, - Filter::FileRelative(file) => f.name.ends_with(file), - Filter::Directory(dir) => f.name.contains(dir), + Filter::FileAbsolute(file) => f.get_file_name() == *file, + Filter::FileRelative(file) => f.get_file_name().ends_with(file), + Filter::Directory(dir) => f.get_file_name().contains(dir), Filter::FunctionInLines(..) | Filter::PLFilter(_) => f.filter_by(filter).is_ok(), Filter::None => true, _ => false, @@ -459,7 +212,7 @@ impl Commit { } impl Iterator for Commit { - type Item = File; + type Item = FileType; fn next(&mut self) -> Option { // get the current function without removing it let function = self.files.get(self.current_iter_pos).cloned(); From 013291eea8e7447eb80c5a49e794bd1d13a8fa70 Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Sun, 9 Oct 2022 17:16:29 -0400 Subject: [PATCH 037/172] rm not-needed.txt --- git-function-history-lib/Cargo.toml | 2 +- structure.txt | 20 -------------------- 2 files changed, 1 insertion(+), 21 deletions(-) delete mode 100644 structure.txt diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 8d1d184f..f6461030 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -18,4 +18,4 @@ chrono = "0.4.22" ra_ap_syntax = "0.0.131" rayon = { version = "1.5.1", optional = true } rustpython-parser = "0.1.2" -enum_dispatch = "0.3.8" + diff --git a/structure.txt b/structure.txt deleted file mode 100644 index de67a210..00000000 --- a/structure.txt +++ /dev/null @@ -1,20 +0,0 @@ -repo: struct {history: Vec} -commit: struct {commit_hash: string commit_date: string ... files: Vec} -filetype: enum {python(python_file), rust(rust_file), ...} all variants implement a common trait -FileTrait trait: { - get_file_name(&self) -> string - get_function(&self) -> Vec - ... -} - -File: struct {file_name: string functions: Vec} -python_file: File where functions is a Vec -rust_file: File where functions is a Vec - - -FunctionTrait trait: { - fmt_with_context(&self, prev option, next option) -> io::Result<()> - ... -} - -functiontrait is implemented by python_function and rust_function, and is not object safe. \ No newline at end of file From d098bba8be70106060f7250b80add703b7673d0e Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Tue, 11 Oct 2022 21:29:07 -0400 Subject: [PATCH 038/172] not using that --- git-function-history-lib/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 8d1d184f..e0d1eb86 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -18,4 +18,3 @@ chrono = "0.4.22" ra_ap_syntax = "0.0.131" rayon = { version = "1.5.1", optional = true } rustpython-parser = "0.1.2" -enum_dispatch = "0.3.8" From 0c8e93cf76fd37e5d52d9d11a99c51ed23c08bdc Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Tue, 11 Oct 2022 22:15:49 -0400 Subject: [PATCH 039/172] added soe more tests parsing a single commit takes one second, parsing files takes milliseonds or less --- git-function-history-lib/src/languages/c.rs | 2 +- git-function-history-lib/src/languages/mod.rs | 26 +++++++++++++ .../src/languages/python.rs | 2 +- .../src/languages/rust.rs | 2 +- git-function-history-lib/src/lib.rs | 38 ++++++++++++++----- 5 files changed, 57 insertions(+), 13 deletions(-) diff --git a/git-function-history-lib/src/languages/c.rs b/git-function-history-lib/src/languages/c.rs index 934b491f..091fcd0f 100644 --- a/git-function-history-lib/src/languages/c.rs +++ b/git-function-history-lib/src/languages/c.rs @@ -64,7 +64,7 @@ pub struct ParentFunction { pub(crate) returns: Option, } -pub(crate) fn find_function_in_commit( +pub(crate) fn find_function_in_file( file_contents: &str, name: &str, ) -> Result, Box> { diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 1375cf46..13d3b62e 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -234,3 +234,29 @@ make_file!(PythonFile, PythonFunction, Python); make_file!(RustFile, RustFunction, Rust); #[cfg(feature = "c_lang")] make_file!(CFile, CFunction, C); + +// make macro that auto genertes the test parse__file_time +macro_rules! make_file_time_test { + ($name:ident, $extname:ident, $function:ident) => { + #[test] + fn $name() { + let file = include_str!(concat!( + "..\\..\\src\\test_functions.", + stringify!($extname) + )); + let start = std::time::Instant::now(); + let ok = $function::find_function_in_file(file, "empty_test"); + let end = std::time::Instant::now(); + println!("{} took {:?}", stringify!($name), end - start); + assert!(ok.is_ok()); + } + }; +} +#[cfg(test)] +mod lang_tests { + use super::*; + make_file_time_test!(python_parses, py, python); + make_file_time_test!(rust_parses, rs, rust); + #[cfg(feature = "c_lang")] + make_file_time_test!(c_parses, c, c); +} diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index ff4e00a7..d6598b1e 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -68,7 +68,7 @@ pub struct ParentFunction { pub(crate) returns: Option, } -pub(crate) fn find_function_in_commit( +pub(crate) fn find_function_in_file( file_contents: &str, name: &str, diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 1c1ae73a..cc51e8e3 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -203,7 +203,7 @@ impl fmt::Display for BlockType { #[allow(clippy::too_many_lines)] // TODO: split this function into smaller functions -pub(crate) fn find_function_in_commit( +pub(crate) fn find_function_in_file( file_contents: &str, name: &str, ) -> Result, Box> { diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 62803838..87c9ef79 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -213,7 +213,7 @@ pub fn get_function_history( || !path.ends_with(".c") || !path.ends_with(".h") { - Err(format!("file is supported: {}", path))?; + Err(format!("file is not supported: {}", path))?; } } } @@ -352,7 +352,7 @@ fn find_function_in_commit_with_filetype( #[cfg(not(feature = "parellel"))] let t = files.iter(); let returns: Vec = t - .filter_map(|file| find_function_in_commit(commit, file, name, langs).ok()) + .filter_map(|file| find_function_in_file_with_commit(commit, file, name, langs).ok()) .collect(); if returns.is_empty() { Err(err)?; @@ -360,7 +360,7 @@ fn find_function_in_commit_with_filetype( Ok(returns) } -fn find_function_in_commit( +fn find_function_in_file_with_commit( commit: &str, file_path: &str, name: &str, @@ -369,16 +369,16 @@ fn find_function_in_commit( let fc = find_file_in_commit(commit, file_path)?; match langs { Language::Rust => { - let functions = rust::find_function_in_commit(&fc, name)?; + let functions = rust::find_function_in_file(&fc, name)?; Ok(FileType::Rust(RustFile::new(name.to_string(), functions))) } #[cfg(feature = "c_lang")] Language::C => { - let functions = languages::c::find_function_in_commit(&fc, name)?; + let functions = languages::c::find_function_in_file(&fc, name)?; Ok(FileType::C(CFile::new(name.to_string(), functions))) } Language::Python => { - let functions = languages::python::find_function_in_commit(&fc, name)?; + let functions = languages::python::find_function_in_file(&fc, name)?; Ok(FileType::Python(PythonFile::new( name.to_string(), functions, @@ -386,16 +386,16 @@ fn find_function_in_commit( } Language::All => match file_path.split('.').last() { Some("rs") => { - let functions = rust::find_function_in_commit(&fc, name)?; + let functions = rust::find_function_in_file(&fc, name)?; Ok(FileType::Rust(RustFile::new(name.to_string(), functions))) } #[cfg(feature = "c_lang")] Some("c" | "h") => { - let functions = languages::c::find_function_in_commit(&fc, name)?; + let functions = languages::c::find_function_in_file(&fc, name)?; Ok(FileType::C(CFile::new(name.to_string(), functions))) } Some("py") => { - let functions = languages::python::find_function_in_commit(&fc, name)?; + let functions = languages::python::find_function_in_file(&fc, name)?; Ok(FileType::Python(PythonFile::new( name.to_string(), functions, @@ -483,7 +483,10 @@ mod tests { &languages::Language::Rust, ); assert!(output.is_err()); - assert_eq!(output.unwrap_err().to_string(), "file is not a rust file"); + assert!(output + .unwrap_err() + .to_string() + .contains("file is not a rust file")); } #[test] fn test_date() { @@ -578,4 +581,19 @@ mod tests { } assert!(output.is_ok()); } + + #[test] + fn parse_commit() { + let commit_hash = "d098bba8be70106060f7250b80add703b7673d0e"; + let now = Utc::now(); + let t = find_function_in_commit_with_filetype( + commit_hash, + "empty_test", + &FileFilterType::None, + languages::Language::All, + ); + let after = Utc::now() - now; + println!("time taken: {}", after.num_seconds()); + assert!(t.is_ok()); + } } From 530498883c19b564785a1e2e1ad84a73b4417b94 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 12 Oct 2022 00:01:46 -0400 Subject: [PATCH 040/172] made tests more sstem indepndnt --- cargo-function-history/Cargo.toml | 2 +- cargo-function-history/src/lib.rs | 2 +- git-function-history-lib/Cargo.toml | 2 +- git-function-history-lib/src/languages/mod.rs | 14 +++++++------- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cargo-function-history/Cargo.toml b/cargo-function-history/Cargo.toml index 3498e140..1cd32c38 100644 --- a/cargo-function-history/Cargo.toml +++ b/cargo-function-history/Cargo.toml @@ -26,4 +26,4 @@ dirs = "4.0.0" simple_file_logger = "0.2.0" log = "0.4" function_history_backend_thread = { path = "../function_history_backend_thread", version = "0.2.2", default-features = false} -tui-input = "0.5.1" \ No newline at end of file +tui-input = "0.6.0" \ No newline at end of file diff --git a/cargo-function-history/src/lib.rs b/cargo-function-history/src/lib.rs index 3164a007..2d119716 100644 --- a/cargo-function-history/src/lib.rs +++ b/cargo-function-history/src/lib.rs @@ -58,7 +58,7 @@ pub fn start_ui(app: Rc>) -> Result<()> { app.scroll_down(); } _ => { - input_backend::to_input_request(Event::Key(key)) + input_backend::to_input_request(&Event::Key(key)) .and_then(|req| app.input_buffer.handle(req)); } }, diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index e0d1eb86..d470dbfe 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -15,6 +15,6 @@ c_lang = [] [dependencies] chrono = "0.4.22" -ra_ap_syntax = "0.0.131" +ra_ap_syntax = "0.0.132" rayon = { version = "1.5.1", optional = true } rustpython-parser = "0.1.2" diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 13d3b62e..7e87adce 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -234,24 +234,24 @@ make_file!(PythonFile, PythonFunction, Python); make_file!(RustFile, RustFunction, Rust); #[cfg(feature = "c_lang")] make_file!(CFile, CFunction, C); - +use std::path::MAIN_SEPARATOR; // make macro that auto genertes the test parse__file_time macro_rules! make_file_time_test { - ($name:ident, $extname:ident, $function:ident) => { + ($name:ident, $extname:ident, $function:ident)=> { #[test] fn $name() { - let file = include_str!(concat!( - "..\\..\\src\\test_functions.", - stringify!($extname) - )); + let file = std::env::current_dir().unwrap().to_path_buf().join(MAIN_SEPARATOR.to_string() + "src" + MAIN_SEPARATOR.to_string().as_str() + "test_functions." + stringify!($extname)); + let file = std::fs::read_to_string(file).unwrap(); let start = std::time::Instant::now(); - let ok = $function::find_function_in_file(file, "empty_test"); + let ok = $function::find_function_in_file(&file, "empty_test"); let end = std::time::Instant::now(); println!("{} took {:?}", stringify!($name), end - start); assert!(ok.is_ok()); } }; } + + #[cfg(test)] mod lang_tests { use super::*; From e8c56f21b1261049017de07a6e068f601bff7a3f Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 12 Oct 2022 00:02:32 -0400 Subject: [PATCH 041/172] buum[pped ra_ap syntax version more --- git-function-history-lib/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index d470dbfe..7063fbe6 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -15,6 +15,6 @@ c_lang = [] [dependencies] chrono = "0.4.22" -ra_ap_syntax = "0.0.132" +ra_ap_syntax = "0.0.133" rayon = { version = "1.5.1", optional = true } rustpython-parser = "0.1.2" From 6467f6e32e6e94fc7770cb59160d5c5ae84637cc Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Wed, 12 Oct 2022 02:16:15 -0400 Subject: [PATCH 042/172] idk --- git-function-history-lib/src/lib.rs | 5 +++-- git-function-history-lib/src/types.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 87c9ef79..bb515084 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -193,7 +193,7 @@ pub fn get_function_history( match langs { #[cfg(feature = "c_lang")] Language::C => { - if !path.ends_with(".c") || !path.ends_with(".h") { + if !path.ends_with(".c") && !path.ends_with(".h") { Err(format!("file is not a c file: {}", path))?; } } @@ -518,13 +518,14 @@ mod tests { "empty_test", &FileFilterType::None, &Filter::None, - &languages::Language::Rust, + &languages::Language::All, ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); match &output { Ok(functions) => { println!("{}", functions); + println!("{:?} functions", functions.get_commit().files); } Err(e) => println!("{}", e), } diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 323d6937..55a76a90 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -84,7 +84,7 @@ impl fmt::Display for FileType { #[derive(Debug, Clone)] pub struct Commit { commit_hash: String, - files: Vec, + pub(crate) files: Vec, pub(crate) date: DateTime, current_iter_pos: usize, current_pos: usize, From 31b2e2b3f0925c8214baffac112dd70094f8b31b Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Wed, 12 Oct 2022 11:34:01 -0400 Subject: [PATCH 043/172] started workig in macro for get_function_history todo: make proper test in the tests module --- git-function-history-lib/src/lib.rs | 50 +++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index bb515084..e490789b 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -248,6 +248,56 @@ pub fn get_function_history( Ok(file_history) } +macro_rules! get_function_history { + ($name:expr) => { + get_function_history($name, &FileFilterType::None, &Filter::None, &Language::All) + }; + ($name:expr, file: $files:expr) => { + get_function_history($name, &$files, &Filter::None, &Language::All) + }; + ($name:expr, filter: $filter:expr) => { + get_function_history($name, &FileFilterType::None, &$filter, &Language::All) + }; + ($name:expr, language: $lang:expr) => { + get_function_history($name, &FileFilterType::None, &Filter::None, &$lang) + }; + ($name:expr, file: $files:expr, filter: $filter:expr) => { + get_function_history($name, &$files, &$filter, &Language::All) + }; + ($name:expr, file: $files:expr, language: $lang:expr) => { + get_function_history($name, &$files, &Filter::None, &$lang) + }; + ($name:expr, filter: $filter:expr, language: $lang:expr) => { + get_function_history($name, &FileFilterType::None, $filter, &$lang) + }; + ($name:expr, file: $files:expr, filter: $filter:expr, language: $lang:expr) => { + get_function_history($name, &$files, &$filter, &$lang) + }; + + + + + + + + +} + +#[test] +fn t_blah() { + let t = "empty_test"; + let t = get_function_history!(t); + match t { + Ok(t) => { + println!("{t}") + } + Err(_) => {} + } + let t = get_function_history!("", file: FileFilterType::None); + let t = get_function_history!("", filter: &Filter::None, language: Language::Rust); + +} + /// List all the commits date in the git history (in rfc2822 format). pub fn get_git_dates() -> Result, Box> { let output = Command::new("git") From 36d998a03851b16a5db1ee1d7879946fc2a4efb0 Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Wed, 12 Oct 2022 11:36:54 -0400 Subject: [PATCH 044/172] cliipied + fmted last commit --- git-function-history-lib/src/languages/mod.rs | 11 ++++++++--- git-function-history-lib/src/languages/python.rs | 2 +- git-function-history-lib/src/lib.rs | 9 --------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 7e87adce..cb568370 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -237,10 +237,16 @@ make_file!(CFile, CFunction, C); use std::path::MAIN_SEPARATOR; // make macro that auto genertes the test parse__file_time macro_rules! make_file_time_test { - ($name:ident, $extname:ident, $function:ident)=> { + ($name:ident, $extname:ident, $function:ident) => { #[test] fn $name() { - let file = std::env::current_dir().unwrap().to_path_buf().join(MAIN_SEPARATOR.to_string() + "src" + MAIN_SEPARATOR.to_string().as_str() + "test_functions." + stringify!($extname)); + let file = std::env::current_dir().unwrap().to_path_buf().join( + MAIN_SEPARATOR.to_string() + + "src" + + MAIN_SEPARATOR.to_string().as_str() + + "test_functions." + + stringify!($extname), + ); let file = std::fs::read_to_string(file).unwrap(); let start = std::time::Instant::now(); let ok = $function::find_function_in_file(&file, "empty_test"); @@ -251,7 +257,6 @@ macro_rules! make_file_time_test { }; } - #[cfg(test)] mod lang_tests { use super::*; diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index d6598b1e..def5a161 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -26,7 +26,7 @@ pub struct PythonFunction { impl fmt::Display for PythonFunction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(ref class) = self.class { - write!(f, "{}", class.top)? + write!(f, "{}", class.top)?; } for parent in &self.parent { write!(f, "{}", parent.top)?; diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index e490789b..6f67c465 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -273,14 +273,6 @@ macro_rules! get_function_history { ($name:expr, file: $files:expr, filter: $filter:expr, language: $lang:expr) => { get_function_history($name, &$files, &$filter, &$lang) }; - - - - - - - - } #[test] @@ -295,7 +287,6 @@ fn t_blah() { } let t = get_function_history!("", file: FileFilterType::None); let t = get_function_history!("", filter: &Filter::None, language: Language::Rust); - } /// List all the commits date in the git history (in rfc2822 format). From f57a02eab182a94ae4345e8a2724e83e068cc64e Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 12 Oct 2022 18:55:21 -0400 Subject: [PATCH 045/172] macro now works fine, like i like it cargo function-histroy now supports languges just need to add c_lang feature --- TODO.md | 3 +- cargo-function-history/src/app/mod.rs | 362 ++++++++++++--------- cargo-function-history/src/main.rs | 41 ++- function_history_backend_thread/src/lib.rs | 8 +- git-function-history-lib/src/lib.rs | 65 ++-- 5 files changed, 292 insertions(+), 187 deletions(-) diff --git a/TODO.md b/TODO.md index 00ce4558..07937bf5 100644 --- a/TODO.md +++ b/TODO.md @@ -23,5 +23,6 @@ - [ ] add more and better ways to filter dates - [x] add filters for git specific stuff like author, committer, etc - [ ] ability to get a git repo from a url using something like git clone - - [ ] add support for other languages (currently only supports rust) + - [/] add support for other languages (currently only supports rust) - [x] save search queries and filters to a file + - [ ] rework the way filters and filefilters are handled ie maybe use a builder pattern diff --git a/cargo-function-history/src/app/mod.rs b/cargo-function-history/src/app/mod.rs index bc0f451c..dfc03e9d 100644 --- a/cargo-function-history/src/app/mod.rs +++ b/cargo-function-history/src/app/mod.rs @@ -313,160 +313,230 @@ impl App { if let Some(name) = iter.next() { // check if there next arg stars with file or filter self.status = Status::Loading; - let search = match iter.next() { - None => { - // if there is no next arg then we are searching for a function - // with the given name - Some(FullCommand::Search( - name.to_string(), - FileFilterType::None, - Filter::None, - Language::Rust, - )) - } - Some(thing) => match thing { - "relative" | "absolute" => { - let file_type = match iter.next() { - Some(filter) => match thing { - "relative" => { - FileFilterType::Relative(filter.to_string()) - } - "absolute" => { - FileFilterType::Absolute(filter.to_string()) - } - _ => FileFilterType::None, - }, - None => { + let mut file = FileFilterType::None; + let mut filter = Filter::None; + let mut lang = Language::All; + // let search = match iter.next() { + // None => { + // // if there is no next arg then we are searching for a function + // // with the given name + // Some(FullCommand::Search( + // name.to_string(), + // FileFilterType::None, + // Filter::None, + // Language::Rust, + // )) + // } + // Some(thing) => match thing { + // "relative" | "absolute" => { + // let file_type = match iter.next() { + // Some(filter) => match thing { + // "relative" => { + // FileFilterType::Relative(filter.to_string()) + // } + // "absolute" => { + // FileFilterType::Absolute(filter.to_string()) + // } + // _ => FileFilterType::None, + // }, + // None => { + // self.status = + // Status::Error("No filter given".to_string()); + // return; + // } + // }; + // let filter = match iter.next() { + // Some(filter) => match filter { + // "date" => { + // let date = iter.next(); + // match date { + // Some(date) => { + // let date = date.replace('_', " "); + // Filter::Date(date) + // } + // None => { + // self.status = Status::Error( + // "No date given".to_string(), + // ); + // return; + // } + // } + // } + // "commit" => { + // let commit = iter.next(); + // match commit { + // Some(commit) => { + // Filter::CommitHash(commit.to_string()) + // } + // None => { + // self.status = Status::Error( + // "No commit given".to_string(), + // ); + // return; + // } + // } + // } + // "date range" => { + // let start = iter.next(); + // let end = iter.next(); + // match (start, end) { + // (Some(start), Some(end)) => { + // let start = start.replace('_', " "); + // let end = end.replace('_', " "); + // Filter::DateRange(start, end) + // } + // _ => { + // self.status = Status::Error( + // "No date range given".to_string(), + // ); + // return; + // } + // } + // } + // _ => { + // self.status = + // Status::Error("No filter given".to_string()); + // return; + // } + // }, + // None => Filter::None, + // }; + // Some(FullCommand::Search( + // name.to_string(), + // file_type, + // filter, + // Language::Rust, + // )) + // } + // "date" | "commit" | "date range" => { + // let filter = match thing { + // "date" => { + // let date = iter.next(); + // match date { + // Some(date) => Filter::Date(date.to_string()), + // None => { + // self.status = + // Status::Error("No date given".to_string()); + // return; + // } + // } + // } + // "commit" => { + // let commit = iter.next(); + // match commit { + // Some(commit) => { + // Filter::CommitHash(commit.to_string()) + // } + // None => { + // self.status = Status::Error( + // "No commit given".to_string(), + // ); + // return; + // } + // } + // } + // "date range" => { + // let start = iter.next(); + // let end = iter.next(); + // match (start, end) { + // (Some(start), Some(end)) => Filter::DateRange( + // start.to_string(), + // end.to_string(), + // ), + // _ => { + // self.status = Status::Error( + // "No date range given".to_string(), + // ); + // return; + // } + // } + // } + // _ => Filter::None, + // }; + // Some(FullCommand::Search( + // name.to_string(), + // FileFilterType::None, + // filter, + // Language::Rust, + // )) + // } + // "language" => { + // let language = iter.next(); + // match language { + // Some(language) => { + // let language = match language { + // "rust" => Language::Rust, + // "python" => Language::Python, + // "c" => Language::C, + // _ => { + // self.status = Status::Error( + // "Invalid language".to_string(), + // ); + // return; + // } + // }; + // Some(FullCommand::Search( + // name.to_string(), + // FileFilterType::None, + // Filter::None, + // language, + // )) + // } + // None => { + // self.status = + // Status::Error("No language given".to_string()); + // return; + // } + // } + // } + // _ => { + // self.status = Status::Error("Invalid file type".to_string()); + // None + // } + // }, + // }; + for i in iter.collect::>().windows(2) { + match i { + ["relative", filepath] => { + file = FileFilterType::Relative(filepath.to_string()); + } + ["absolute", filepath] => { + file = FileFilterType::Absolute(filepath.to_string()); + } + ["date", date] => { + filter = Filter::Date(date.to_string()); + } + ["commit", commit] => { + filter = Filter::CommitHash(commit.to_string()); + } + ["date range", start, end] => { + filter = Filter::DateRange(start.to_string(), end.to_string()); + } + ["language", language] => { + lang = match language { + &"rust" => Language::Rust, + &"python" => Language::Python, + #[cfg(feature = "c_lang")] + &"c" => Language::C, + _ => { self.status = - Status::Error("No filter given".to_string()); + Status::Error("Invalid language".to_string()); return; } }; - let filter = match iter.next() { - Some(filter) => match filter { - "date" => { - let date = iter.next(); - match date { - Some(date) => { - let date = date.replace('_', " "); - Filter::Date(date) - } - None => { - self.status = Status::Error( - "No date given".to_string(), - ); - return; - } - } - } - "commit" => { - let commit = iter.next(); - match commit { - Some(commit) => { - Filter::CommitHash(commit.to_string()) - } - None => { - self.status = Status::Error( - "No commit given".to_string(), - ); - return; - } - } - } - "date range" => { - let start = iter.next(); - let end = iter.next(); - match (start, end) { - (Some(start), Some(end)) => { - let start = start.replace('_', " "); - let end = end.replace('_', " "); - Filter::DateRange(start, end) - } - _ => { - self.status = Status::Error( - "No date range given".to_string(), - ); - return; - } - } - } - _ => { - self.status = - Status::Error("No filter given".to_string()); - return; - } - }, - None => Filter::None, - }; - - Some(FullCommand::Search( - name.to_string(), - file_type, - filter, - Language::Rust, - )) - } - "date" | "commit" | "date range" => { - let filter = match thing { - "date" => { - let date = iter.next(); - match date { - Some(date) => Filter::Date(date.to_string()), - None => { - self.status = - Status::Error("No date given".to_string()); - return; - } - } - } - "commit" => { - let commit = iter.next(); - match commit { - Some(commit) => { - Filter::CommitHash(commit.to_string()) - } - None => { - self.status = Status::Error( - "No commit given".to_string(), - ); - return; - } - } - } - "date range" => { - let start = iter.next(); - let end = iter.next(); - match (start, end) { - (Some(start), Some(end)) => Filter::DateRange( - start.to_string(), - end.to_string(), - ), - _ => { - self.status = Status::Error( - "No date range given".to_string(), - ); - return; - } - } - } - _ => Filter::None, - }; - Some(FullCommand::Search( - name.to_string(), - FileFilterType::None, - filter, - Language::Rust, - )) } + _ => { - self.status = Status::Error("Invalid file type".to_string()); - None + self.status = Status::Error(format!("Invalid search {}", i[0])); + return; } - }, - }; - if let Some(search) = search { - self.channels.0.send(search).unwrap(); + } } + + self.channels + .0 + .send(FullCommand::Search(name.to_string(), file, filter, lang)) + .unwrap(); } else { self.status = Status::Error("No function name given".to_string()); } diff --git a/cargo-function-history/src/main.rs b/cargo-function-history/src/main.rs index 7bd20320..f6e83a9d 100644 --- a/cargo-function-history/src/main.rs +++ b/cargo-function-history/src/main.rs @@ -20,7 +20,7 @@ fn main() -> Result<(), Box> { string, config.file_type, config.filter, - git_function_history::languages::Language::Rust, + config.language, ))?; Status::Loading } @@ -38,7 +38,10 @@ fn usage() -> ! { println!(" --file-relative - search any file ending with the filename specified after the function name"); println!(" --filter-date= - filter to the given date"); println!(" --filter-commit-hash= - filter to the given commit hash"); - println!(" --filter-date-range=: - filter to the given date range"); + println!(" --filter-date-range=: - filter to the given date range"); + println!(" --lang=[lang] - filter to the given language"); + println!(" Available languages: rust, python, c, all"); + println!(" Default: all"); exit(1); } @@ -47,6 +50,7 @@ struct Config { function_name: String, filter: Filter, file_type: FileFilterType, + language: git_function_history::languages::Language, } fn parse_args() -> Config { @@ -54,10 +58,13 @@ fn parse_args() -> Config { function_name: String::new(), filter: Filter::None, file_type: FileFilterType::None, + language: git_function_history::languages::Language::All, }; env::args().enumerate().skip(1).for_each(|arg| { if arg.0 == 1 { - println!("{}", arg.1); + if arg.1 == "--help" { + usage(); + } match arg.1.split_once(':') { Some(string_tuple) => { config.file_type = FileFilterType::Relative(string_tuple.1.replace('\\', "/")); @@ -134,6 +141,34 @@ fn parse_args() -> Config { }; config.filter = Filter::DateRange(date_range.0.to_string(), date_range.1.to_string()); } + string if string.starts_with("--lang=") => { + let lang = match string.split('=').nth(1) { + Some(string) => string, + None => { + eprintln!("Error no language specified"); + exit(1); + } + }; + match lang { + "rust" => { + config.language = git_function_history::languages::Language::Rust; + } + "python" => { + config.language = git_function_history::languages::Language::Python; + } + #[cfg(feature = "c_lang")] + "c" => { + config.language = git_function_history::languages::Language::C; + } + "all" => { + config.language = git_function_history::languages::Language::All; + } + _ => { + eprintln!("Error invalid language specified"); + exit(1); + } + } + } _ => { println!("Error:\n\tUnknown argument: {}\n\tTip: use --help to see available arguments.", arg.1); exit(1); diff --git a/function_history_backend_thread/src/lib.rs b/function_history_backend_thread/src/lib.rs index cbd7d0d3..edb0679a 100644 --- a/function_history_backend_thread/src/lib.rs +++ b/function_history_backend_thread/src/lib.rs @@ -89,7 +89,13 @@ pub fn command_thread( } FullCommand::Search(name, file, filter, lang) => { if log { - log::info!("Searching for {} in {:?}", name, file); + log::info!( + "Searching for {} in {:?} with language {} and filter {:?}", + name, + file, + lang, + filter + ); } match get_function_history(&name, &file, &filter, &lang) { Ok(functions) => { diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 6f67c465..93f8d0c7 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -248,45 +248,38 @@ pub fn get_function_history( Ok(file_history) } -macro_rules! get_function_history { - ($name:expr) => { - get_function_history($name, &FileFilterType::None, &Filter::None, &Language::All) - }; - ($name:expr, file: $files:expr) => { - get_function_history($name, &$files, &Filter::None, &Language::All) - }; - ($name:expr, filter: $filter:expr) => { - get_function_history($name, &FileFilterType::None, &$filter, &Language::All) - }; - ($name:expr, language: $lang:expr) => { - get_function_history($name, &FileFilterType::None, &Filter::None, &$lang) - }; - ($name:expr, file: $files:expr, filter: $filter:expr) => { - get_function_history($name, &$files, &$filter, &Language::All) - }; - ($name:expr, file: $files:expr, language: $lang:expr) => { - get_function_history($name, &$files, &Filter::None, &$lang) - }; - ($name:expr, filter: $filter:expr, language: $lang:expr) => { - get_function_history($name, &FileFilterType::None, $filter, &$lang) - }; - ($name:expr, file: $files:expr, filter: $filter:expr, language: $lang:expr) => { - get_function_history($name, &$files, &$filter, &$lang) - }; +struct MacroOpts<'a> { + name: &'a str, + file: FileFilterType, + filter: Filter, + language: Language, } -#[test] -fn t_blah() { - let t = "empty_test"; - let t = get_function_history!(t); - match t { - Ok(t) => { - println!("{t}") +impl Default for MacroOpts<'_> { + fn default() -> Self { + Self { + name: "", + file: FileFilterType::None, + filter: Filter::None, + language: Language::All, } - Err(_) => {} } - let t = get_function_history!("", file: FileFilterType::None); - let t = get_function_history!("", filter: &Filter::None, language: Language::Rust); +} + +#[macro_export] +macro_rules! get_function_history { + ($($variant:ident = $value:expr),*) => {{ + let mut opts = MacroOpts::default(); + $( + opts.$variant = $value; + )* + get_function_history( + &opts.name, + &opts.file, + &opts.filter, + &opts.language + ) + }}; } /// List all the commits date in the git history (in rfc2822 format). @@ -365,7 +358,6 @@ fn find_function_in_commit_with_filetype( } Language::Python => { if file.ends_with(".py") { - // panic!("{:?}", file); files.push(file); } } @@ -377,6 +369,7 @@ fn find_function_in_commit_with_filetype( Language::All => { if file.ends_with(".rs") || file.ends_with(".py") + // TODO: use cfg!() macro to check if c_lang is enabled || file.ends_with(".c") || file.ends_with(".h") { From 5724d9c7b9106503692fc0fdc00d46a32a243313 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 12 Oct 2022 20:59:02 -0400 Subject: [PATCH 046/172] messily fixed macro scoping fixed examples in docs fixed name of files being function name instead of filename --- git-function-history-lib/src/languages/mod.rs | 13 ++-- .../src/languages/python.rs | 1 - git-function-history-lib/src/lib.rs | 64 ++++++++++++++----- git-function-history-lib/src/types.rs | 6 +- 4 files changed, 57 insertions(+), 27 deletions(-) diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index cb568370..2dbeb19f 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -240,14 +240,11 @@ macro_rules! make_file_time_test { ($name:ident, $extname:ident, $function:ident) => { #[test] fn $name() { - let file = std::env::current_dir().unwrap().to_path_buf().join( - MAIN_SEPARATOR.to_string() - + "src" - + MAIN_SEPARATOR.to_string().as_str() - + "test_functions." - + stringify!($extname), - ); - let file = std::fs::read_to_string(file).unwrap(); + let mut file = std::env::current_dir().unwrap(); + file.push("src"); + file.push("test_functions.".to_string() + stringify!($extname)); + let file = std::fs::read_to_string(file.clone()) + .expect(format!("could not read file {:?}", file).as_str()); let start = std::time::Instant::now(); let ok = $function::find_function_in_file(&file, "empty_test"); let end = std::time::Instant::now(); diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index def5a161..e3eb9ebf 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -70,7 +70,6 @@ pub struct ParentFunction { pub(crate) fn find_function_in_file( file_contents: &str, - name: &str, ) -> Result, Box> { let ast = parser::parse_program(file_contents)?; diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 93f8d0c7..00289bd9 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -31,7 +31,7 @@ use languages::CFile; use std::{error::Error, process::Command}; pub use types::{Commit, FunctionHistory}; -use crate::languages::Language; +pub use crate::languages::Language; /// Different filetypes that can be used to ease the process of finding functions using `get_function_history`. #[derive(Debug, Clone, PartialEq, Eq)] @@ -102,8 +102,8 @@ pub enum Filter { /// # examples /// /// ``` -/// use git_function_history::{get_function_history, Filter, FileType}; -/// let t = get_function_history("empty_test", FileType::Absolute("src/test_functions.rs".to_string()), Filter::None); +/// use git_function_history::{get_function_history, Filter, FileFilterType, Language}; +/// let t = get_function_history("empty_test", &FileFilterType::Absolute("src/test_functions.rs".to_string()), &Filter::None, &Language::Rust).unwrap(); /// ``` #[allow(clippy::too_many_lines)] // TODO: split this function into smaller functions @@ -248,11 +248,12 @@ pub fn get_function_history( Ok(file_history) } -struct MacroOpts<'a> { - name: &'a str, - file: FileFilterType, - filter: Filter, - language: Language, +/// used for the `get_function_history` macro internally (you don't have to touch this) +pub struct MacroOpts<'a> { + pub name: &'a str, + pub file: FileFilterType, + pub filter: Filter, + pub language: Language, } impl Default for MacroOpts<'_> { @@ -266,10 +267,37 @@ impl Default for MacroOpts<'_> { } } +/// macro to get the history of a function +/// wrapper around the `get_function_history` function +/// +/// # examples +/// ```rust +/// use git_function_history::{get_function_history, languages::Language, Filter, FileFilterType}; +/// git_function_history::get_function_history!(name = "main", file = FileFilterType::Relative("src/main.rs".to_string()), filter = Filter::None, language = Language::Rust); +/// ``` +/// +/// everything is optional but the name, and in no particular order +/// +/// ```rust +/// use git_function_history::{get_function_history, FileFilterType}; +/// git_function_history::get_function_history!(name = "main", file = FileFilterType::Relative("src/main.rs".to_string())); +/// ``` +/// +/// ```rust +/// +/// use git_function_history::{get_function_history, Filter, FileFilterType}; +/// git_function_history::get_function_history!(name = "main", filter = Filter::None, file = FileFilterType::Relative("src/main.rs".to_string())); +/// ``` +/// +/// Default values are: +/// +/// - file: `FileFilterType::None` +/// - filter: `Filter::None` +/// - language: `Language::All` #[macro_export] macro_rules! get_function_history { ($($variant:ident = $value:expr),*) => {{ - let mut opts = MacroOpts::default(); + let mut opts = $crate::MacroOpts::default(); $( opts.$variant = $value; )* @@ -404,34 +432,40 @@ fn find_function_in_file_with_commit( match langs { Language::Rust => { let functions = rust::find_function_in_file(&fc, name)?; - Ok(FileType::Rust(RustFile::new(name.to_string(), functions))) + Ok(FileType::Rust(RustFile::new( + file_path.to_string(), + functions, + ))) } #[cfg(feature = "c_lang")] Language::C => { let functions = languages::c::find_function_in_file(&fc, name)?; - Ok(FileType::C(CFile::new(name.to_string(), functions))) + Ok(FileType::C(CFile::new(file_path.to_string(), functions))) } Language::Python => { let functions = languages::python::find_function_in_file(&fc, name)?; Ok(FileType::Python(PythonFile::new( - name.to_string(), + file_path.to_string(), functions, ))) } Language::All => match file_path.split('.').last() { Some("rs") => { let functions = rust::find_function_in_file(&fc, name)?; - Ok(FileType::Rust(RustFile::new(name.to_string(), functions))) + Ok(FileType::Rust(RustFile::new( + file_path.to_string(), + functions, + ))) } #[cfg(feature = "c_lang")] Some("c" | "h") => { let functions = languages::c::find_function_in_file(&fc, name)?; - Ok(FileType::C(CFile::new(name.to_string(), functions))) + Ok(FileType::C(CFile::new(file_path.to_string(), functions))) } Some("py") => { let functions = languages::python::find_function_in_file(&fc, name)?; Ok(FileType::Python(PythonFile::new( - name.to_string(), + file_path.to_string(), functions, ))) } diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 55a76a90..a95cb2d0 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -322,11 +322,11 @@ impl FunctionHistory { /// /// # examples /// ```rust - /// use git_function_history::{get_function_history, Filter, FileType}; + /// use git_function_history::{get_function_history, Filter, FileFilterType, Language}; /// - /// let history = get_function_history("new", FileType::None, Filter::None).unwrap(); + /// let history = get_function_history("new", &FileFilterType::None, &Filter::None, &Language::Rust).unwrap(); /// - /// history.filter_by(Filter::Directory("app".to_string())).unwrap(); + /// history.filter_by(&Filter::Directory("app".to_string())).unwrap(); /// ``` pub fn filter_by(&self, filter: &Filter) -> Result> { #[cfg(feature = "parallel")] From 6da25f1a5906a095437f79eb7a2f1c4841e82608 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 13 Oct 2022 10:25:25 -0400 Subject: [PATCH 047/172] gui: added scrollbar to command builder & now supports other languages --- cargo-function-history/Cargo.toml | 1 + function_history_backend_thread/Cargo.toml | 1 + git-function-history-gui/Cargo.toml | 1 + git-function-history-gui/src/lib.rs | 627 +++++++++++---------- git-function-history-lib/src/lib.rs | 4 +- 5 files changed, 347 insertions(+), 287 deletions(-) diff --git a/cargo-function-history/Cargo.toml b/cargo-function-history/Cargo.toml index 1cd32c38..28d4c1cd 100644 --- a/cargo-function-history/Cargo.toml +++ b/cargo-function-history/Cargo.toml @@ -14,6 +14,7 @@ description = "cargo frontend for git-function-history" default = ["parallel"] parallel = ["git_function_history/parallel", "function_history_backend_thread/parallel"] not-parallel = [] +c_lang = ["function_history_backend_thread/c_lang", "git_function_history/c_lang"] [dependencies] git_function_history = { path = "../git-function-history-lib", version = "0.6.2", default-features = false} diff --git a/function_history_backend_thread/Cargo.toml b/function_history_backend_thread/Cargo.toml index 32992749..a19e578a 100644 --- a/function_history_backend_thread/Cargo.toml +++ b/function_history_backend_thread/Cargo.toml @@ -15,6 +15,7 @@ description = "threading and types for git-function-history" default = ["parallel"] parallel = ["git_function_history/parallel"] not-parallel = [] +c_lang = ["git_function_history/c_lang"] [dependencies] git_function_history = { path = "../git-function-history-lib", version = "0.6.2", default-features = false} diff --git a/git-function-history-gui/Cargo.toml b/git-function-history-gui/Cargo.toml index 1489db6d..1d905c0c 100644 --- a/git-function-history-gui/Cargo.toml +++ b/git-function-history-gui/Cargo.toml @@ -14,6 +14,7 @@ description = "GUI frontend for git-function-history" default = ["parallel"] parallel = ["git_function_history/parallel", "function_history_backend_thread/parallel"] not-parallel = [] +c_lang = ["git_function_history/c_lang", "function_history_backend_thread/c_lang"] [dependencies] eframe = {version = "0.19.0", features = ["dark-light"]} diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index 3cdda7cf..9c8e0344 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -31,6 +31,7 @@ pub struct MyEguiApp { filter: Filter, file_type: FileFilterType, history_filter_type: HistoryFilterType, + language: Language, } impl MyEguiApp { @@ -52,6 +53,7 @@ impl MyEguiApp { file_type: FileFilterType::None, filter: Filter::None, history_filter_type: HistoryFilterType::None, + language: Language::All, } } @@ -279,334 +281,387 @@ impl eframe::App for MyEguiApp { }); egui::TopBottomPanel::bottom("commnad_builder").show(ctx, |ui| { egui::menu::bar(ui, |ui| { - let max = ui.available_width() / 6.0; - egui::ComboBox::from_id_source("command_combo_box") - .selected_text(self.command.to_string()) - .show_ui(ui, |ui| { - ui.selectable_value(&mut self.command, Command::Filter, "filter"); - ui.selectable_value(&mut self.command, Command::Search, "search"); - ui.selectable_value(&mut self.command, Command::List, "list"); - }); - match self.command { - Command::Filter => { - match &self.cmd_output { - CommandResult::History(_) => { - // Options 1. by date 2. by commit hash 3. in date range 4. function in block 5. function in lines 6. function in function - let text = match &self.history_filter_type { - HistoryFilterType::None => "filter type".to_string(), - a => a.to_string(), + egui::ScrollArea::horizontal() + .max_height(f32::INFINITY) + .max_width(f32::INFINITY) + .auto_shrink([false, false]) + .show(ui, |ui| { + let max = ui.available_width() / 6.0; + egui::ComboBox::from_id_source("command_combo_box") + .selected_text(self.command.to_string()) + .show_ui(ui, |ui| { + ui.selectable_value(&mut self.command, Command::Filter, "filter"); + ui.selectable_value(&mut self.command, Command::Search, "search"); + ui.selectable_value(&mut self.command, Command::List, "list"); + }); + match self.command { + Command::Filter => { + match &self.cmd_output { + CommandResult::History(_) => { + // Options 1. by date 2. by commit hash 3. in date range 4. function in block 5. function in lines 6. function in function + let text = match &self.history_filter_type { + HistoryFilterType::None => "filter type".to_string(), + a => a.to_string(), + }; + egui::ComboBox::from_id_source("history_combo_box") + .selected_text(text) + .show_ui(ui, |ui| { + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::Date(String::new()), + "by date", + ); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::CommitHash(String::new()), + "by commit hash", + ); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::DateRange( + String::new(), + String::new(), + ), + "in date range", + ); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::FunctionInBlock( + String::new(), + ), + "function in block", + ); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::FunctionInLines( + String::new(), + String::new(), + ), + "function in lines", + ); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::FunctionInFunction( + String::new(), + ), + "function in function", + ); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::FileAbsolute(String::new()), + "file absolute", + ); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::FileRelative(String::new()), + "file relative", + ); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::Directory(String::new()), + "directory", + ); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::None, + "none", + ); + }); + match &mut self.history_filter_type { + HistoryFilterType::DateRange(line1, line2) + | HistoryFilterType::FunctionInLines(line1, line2) => { + ui.horizontal(|ui| { + // set the width of the input field + ui.set_min_width(4.0); + ui.set_max_width(max); + ui.add(TextEdit::singleline(line1)); + }); + ui.horizontal(|ui| { + // set the width of the input field + ui.set_min_width(4.0); + ui.set_max_width(max); + ui.add(TextEdit::singleline(line2)); + }); + } + HistoryFilterType::Date(dir) + | HistoryFilterType::CommitHash(dir) + | HistoryFilterType::FunctionInBlock(dir) + | HistoryFilterType::FunctionInFunction(dir) + | HistoryFilterType::FileAbsolute(dir) + | HistoryFilterType::FileRelative(dir) + | HistoryFilterType::Directory(dir) => { + ui.horizontal(|ui| { + // set the width of the input field + ui.set_min_width(4.0); + ui.set_max_width(max); + ui.add(TextEdit::singleline(dir)); + }); + } + HistoryFilterType::None => { + // do nothing + } + } + let resp = ui.add(Button::new("Go")); + if resp.clicked() { + self.status = Status::Loading; + let filter = match &self.history_filter_type { + HistoryFilterType::Date(date) => { + Some(Filter::Date(date.to_string())) + } + HistoryFilterType::CommitHash(commit_hash) => Some( + Filter::CommitHash(commit_hash.to_string()), + ), + HistoryFilterType::DateRange(date1, date2) => { + Some(Filter::DateRange( + date1.to_string(), + date2.to_string(), + )) + } + HistoryFilterType::FunctionInBlock(_block) => None, + // Some( + // Filter::FunctionInBlock(BlockType::from_string(block)), + // ), + HistoryFilterType::FunctionInLines( + line1, + line2, + ) => { + let fn_in_lines = ( + match line1.parse::() { + Ok(x) => x, + Err(e) => { + self.status = + Status::Error(format!("{}", e)); + return; + } + }, + match line2.parse::() { + Ok(x) => x, + Err(e) => { + self.status = + Status::Error(format!("{}", e)); + return; + } + }, + ); + Some(Filter::FunctionInLines( + fn_in_lines.0, + fn_in_lines.1, + )) + } + HistoryFilterType::FunctionInFunction( + _function, + ) => { + // Some(Filter::FunctionWithParent(function.to_string())) + None + } + HistoryFilterType::FileAbsolute(file) => { + Some(Filter::FileAbsolute(file.to_string())) + } + HistoryFilterType::FileRelative(file) => { + Some(Filter::FileRelative(file.to_string())) + } + HistoryFilterType::Directory(dir) => { + Some(Filter::Directory(dir.to_string())) + } + HistoryFilterType::None => { + self.status = Status::Ok(None); + None + } + }; + if let Some(filter) = filter { + self.channels + .0 + .send(FullCommand::Filter(FilterType { + thing: self.cmd_output.clone(), + filter, + })) + .unwrap(); + } + } + } + + _ => { + ui.add(Label::new("No filters available")); + } + } + } + Command::Search => { + ui.add(Label::new("Function Name:")); + ui.horizontal(|ui| { + // set the width of the input field + ui.set_min_width(4.0); + ui.set_max_width(max); + ui.add(TextEdit::singleline(&mut self.input_buffer)); + }); + + let text = match &self.file_type { + FileFilterType::Directory(_) => "directory", + FileFilterType::Absolute(_) => "absolute", + FileFilterType::Relative(_) => "relative", + _ => "file type", }; - egui::ComboBox::from_id_source("history_combo_box") + egui::ComboBox::from_id_source("search_file_combo_box") .selected_text(text) .show_ui(ui, |ui| { ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::Date(String::new()), - "by date", - ); - ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::CommitHash(String::new()), - "by commit hash", - ); - ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::DateRange( - String::new(), - String::new(), - ), - "in date range", - ); - ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::FunctionInBlock(String::new()), - "function in block", + &mut self.file_type, + FileFilterType::None, + "None", ); ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::FunctionInLines( - String::new(), - String::new(), - ), - "function in lines", + &mut self.file_type, + FileFilterType::Relative(String::new()), + "Relative", ); ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::FunctionInFunction(String::new()), - "function in function", + &mut self.file_type, + FileFilterType::Absolute(String::new()), + "Absolute", ); ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::FileAbsolute(String::new()), - "file absolute", + &mut self.file_type, + FileFilterType::Directory(String::new()), + "Directory", ); + }); + match &mut self.file_type { + FileFilterType::None => {} + FileFilterType::Relative(dir) + | FileFilterType::Absolute(dir) + | FileFilterType::Directory(dir) => { + ui.horizontal(|ui| { + // set the width of the input field + ui.set_min_width(4.0); + ui.set_max_width(max); + ui.add(TextEdit::singleline(dir)); + }); + } + } + // get filters if any + let text = match &self.filter { + Filter::CommitHash(_) => "commit hash".to_string(), + Filter::DateRange(..) => "date range".to_string(), + Filter::Date(_) => "date".to_string(), + _ => "filter type".to_string(), + }; + egui::ComboBox::from_id_source("search_search_filter_combo_box") + .selected_text(text) + .show_ui(ui, |ui| { + ui.selectable_value(&mut self.filter, Filter::None, "None"); ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::FileRelative(String::new()), - "file relative", + &mut self.filter, + Filter::CommitHash(String::new()), + "Commit Hash", ); ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::Directory(String::new()), - "directory", + &mut self.filter, + Filter::Date(String::new()), + "Date", ); ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::None, - "none", + &mut self.filter, + Filter::DateRange(String::new(), String::new()), + "Date Range", ); }); - match &mut self.history_filter_type { - HistoryFilterType::DateRange(line1, line2) - | HistoryFilterType::FunctionInLines(line1, line2) => { + + // let + match &mut self.filter { + Filter::None => {} + Filter::CommitHash(thing) | Filter::Date(thing) => { ui.horizontal(|ui| { // set the width of the input field ui.set_min_width(4.0); ui.set_max_width(max); - ui.add(TextEdit::singleline(line1)); + ui.add(TextEdit::singleline(thing)); }); + } + Filter::DateRange(start, end) => { ui.horizontal(|ui| { // set the width of the input field ui.set_min_width(4.0); ui.set_max_width(max); - ui.add(TextEdit::singleline(line2)); + ui.add(TextEdit::singleline(start)); }); - } - HistoryFilterType::Date(dir) - | HistoryFilterType::CommitHash(dir) - | HistoryFilterType::FunctionInBlock(dir) - | HistoryFilterType::FunctionInFunction(dir) - | HistoryFilterType::FileAbsolute(dir) - | HistoryFilterType::FileRelative(dir) - | HistoryFilterType::Directory(dir) => { + ui.add(Label::new("-")); ui.horizontal(|ui| { // set the width of the input field ui.set_min_width(4.0); ui.set_max_width(max); - ui.add(TextEdit::singleline(dir)); + ui.add(TextEdit::singleline(end)); }); } - HistoryFilterType::None => { - // do nothing - } + _ => {} } + let text = match self.language { + Language::Rust => "Rust", + #[cfg(feature = "c_lang")] + Language::C => "C", + + Language::Python => "Python", + Language::All => "Language", + }; + egui::ComboBox::from_id_source("search_language_combo_box") + .selected_text(text) + .show_ui(ui, |ui| { + ui.selectable_value( + &mut self.language, + Language::Rust, + "Rust", + ); + #[cfg(feature = "c_lang")] + ui.selectable_value(&mut self.language, Language::C, "C"); + ui.selectable_value( + &mut self.language, + Language::Python, + "Python", + ); + ui.selectable_value( + &mut self.language, + Language::All, + "All", + ); + }); let resp = ui.add(Button::new("Go")); if resp.clicked() { self.status = Status::Loading; - let filter = match &self.history_filter_type { - HistoryFilterType::Date(date) => { - Some(Filter::Date(date.to_string())) - } - HistoryFilterType::CommitHash(commit_hash) => { - Some(Filter::CommitHash(commit_hash.to_string())) - } - HistoryFilterType::DateRange(date1, date2) => Some( - Filter::DateRange(date1.to_string(), date2.to_string()), - ), - HistoryFilterType::FunctionInBlock(_block) => None, - // Some( - // Filter::FunctionInBlock(BlockType::from_string(block)), - // ), - HistoryFilterType::FunctionInLines(line1, line2) => { - let fn_in_lines = ( - match line1.parse::() { - Ok(x) => x, - Err(e) => { - self.status = - Status::Error(format!("{}", e)); - return; - } - }, - match line2.parse::() { - Ok(x) => x, - Err(e) => { - self.status = - Status::Error(format!("{}", e)); - return; - } - }, - ); - Some(Filter::FunctionInLines( - fn_in_lines.0, - fn_in_lines.1, - )) - } - HistoryFilterType::FunctionInFunction(_function) => { - // Some(Filter::FunctionWithParent(function.to_string())) - None - } - HistoryFilterType::FileAbsolute(file) => { - Some(Filter::FileAbsolute(file.to_string())) - } - HistoryFilterType::FileRelative(file) => { - Some(Filter::FileRelative(file.to_string())) - } - HistoryFilterType::Directory(dir) => { - Some(Filter::Directory(dir.to_string())) - } - HistoryFilterType::None => { - self.status = Status::Ok(None); - None - } - }; - if let Some(filter) = filter { - self.channels - .0 - .send(FullCommand::Filter(FilterType { - thing: self.cmd_output.clone(), - filter, - })) - .unwrap(); - } + self.channels + .0 + .send(FullCommand::Search( + self.input_buffer.clone(), + self.file_type.clone(), + self.filter.clone(), + Language::Rust, + )) + .unwrap(); } } - - _ => { - ui.add(Label::new("No filters available")); - } - } - } - Command::Search => { - ui.add(Label::new("Function Name:")); - ui.horizontal(|ui| { - // set the width of the input field - ui.set_min_width(4.0); - ui.set_max_width(max); - ui.add(TextEdit::singleline(&mut self.input_buffer)); - }); - - let text = match &self.file_type { - FileFilterType::Directory(_) => "directory", - FileFilterType::Absolute(_) => "absolute", - FileFilterType::Relative(_) => "relative", - _ => "file type", - }; - egui::ComboBox::from_id_source("search_file_combo_box") - .selected_text(text) - .show_ui(ui, |ui| { - ui.selectable_value( - &mut self.file_type, - FileFilterType::None, - "None", - ); - ui.selectable_value( - &mut self.file_type, - FileFilterType::Relative(String::new()), - "Relative", - ); - ui.selectable_value( - &mut self.file_type, - FileFilterType::Absolute(String::new()), - "Absolute", - ); - ui.selectable_value( - &mut self.file_type, - FileFilterType::Directory(String::new()), - "Directory", - ); - }); - match &mut self.file_type { - FileFilterType::None => {} - FileFilterType::Relative(dir) - | FileFilterType::Absolute(dir) - | FileFilterType::Directory(dir) => { - ui.horizontal(|ui| { - // set the width of the input field - ui.set_min_width(4.0); - ui.set_max_width(max); - ui.add(TextEdit::singleline(dir)); - }); - } - } - // get filters if any - let text = match &self.filter { - Filter::CommitHash(_) => "commit hash".to_string(), - Filter::DateRange(..) => "date range".to_string(), - Filter::Date(_) => "date".to_string(), - _ => "filter type".to_string(), - }; - egui::ComboBox::from_id_source("search_search_filter_combo_box") - .selected_text(text) - .show_ui(ui, |ui| { - ui.selectable_value(&mut self.filter, Filter::None, "None"); - ui.selectable_value( - &mut self.filter, - Filter::CommitHash(String::new()), - "Commit Hash", - ); - ui.selectable_value( - &mut self.filter, - Filter::Date(String::new()), - "Date", - ); - ui.selectable_value( - &mut self.filter, - Filter::DateRange(String::new(), String::new()), - "Date Range", - ); - }); - match &mut self.filter { - Filter::None => {} - Filter::CommitHash(thing) | Filter::Date(thing) => { - ui.horizontal(|ui| { - // set the width of the input field - ui.set_min_width(4.0); - ui.set_max_width(max); - ui.add(TextEdit::singleline(thing)); - }); - } - Filter::DateRange(start, end) => { - ui.horizontal(|ui| { - // set the width of the input field - ui.set_min_width(4.0); - ui.set_max_width(max); - ui.add(TextEdit::singleline(start)); - }); - ui.add(Label::new("-")); - ui.horizontal(|ui| { - // set the width of the input field - ui.set_min_width(4.0); - ui.set_max_width(max); - ui.add(TextEdit::singleline(end)); - }); + Command::List => { + egui::ComboBox::from_id_source("list_type") + .selected_text(self.list_type.to_string()) + .show_ui(ui, |ui| { + ui.selectable_value( + &mut self.list_type, + ListType::Dates, + "dates", + ); + ui.selectable_value( + &mut self.list_type, + ListType::Commits, + "commits", + ); + }); + let resp = ui.add(Button::new("Go")); + if resp.clicked() { + self.status = Status::Loading; + self.channels + .0 + .send(FullCommand::List(self.list_type)) + .unwrap(); + } } - _ => {} - } - let resp = ui.add(Button::new("Go")); - if resp.clicked() { - self.status = Status::Loading; - self.channels - .0 - .send(FullCommand::Search( - self.input_buffer.clone(), - self.file_type.clone(), - self.filter.clone(), - Language::Rust, - )) - .unwrap(); } - } - Command::List => { - egui::ComboBox::from_id_source("list_type") - .selected_text(self.list_type.to_string()) - .show_ui(ui, |ui| { - ui.selectable_value(&mut self.list_type, ListType::Dates, "dates"); - ui.selectable_value( - &mut self.list_type, - ListType::Commits, - "commits", - ); - }); - let resp = ui.add(Button::new("Go")); - if resp.clicked() { - self.status = Status::Loading; - self.channels - .0 - .send(FullCommand::List(self.list_type)) - .unwrap(); - } - } - } + }); }); }); diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 00289bd9..b8d6ae2b 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -593,7 +593,9 @@ mod tests { match &output { Ok(functions) => { println!("{}", functions); - println!("{:?} functions", functions.get_commit().files); + functions.get_commit().files.iter().for_each(|file| { + println!("{}", file); + }); } Err(e) => println!("{}", e), } From 813867c8137fdb4dfc483e345bdd3718c577fd9a Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Thu, 13 Oct 2022 14:26:08 +0000 Subject: [PATCH 048/172] update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fa0797b..3f3f8693 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,10 @@ All notable changes to this project will be documented in this file. - Trying to fix changelog +### Gui + +- Added scrollbar to command builder & now supports other languages + ### Lib - Moved away from using mostly enerics to using enums From 390b7d7f1fd779fad24358bf4b2f06f5a4091502 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 13 Oct 2022 21:12:38 -0400 Subject: [PATCH 049/172] started working on more lagnuages --- git-function-history-lib/Cargo.toml | 6 +- git-function-history-lib/README.md | 3 +- git-function-history-lib/src/languages/go.rs | 217 ++++++++++++++++++ .../src/languages/java.rs | 0 git-function-history-lib/src/languages/mod.rs | 8 +- .../src/languages/ruby.rs | 0 6 files changed, 231 insertions(+), 3 deletions(-) create mode 100644 git-function-history-lib/src/languages/go.rs create mode 100644 git-function-history-lib/src/languages/java.rs create mode 100644 git-function-history-lib/src/languages/ruby.rs diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 7063fbe6..72a5e91b 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -9,12 +9,16 @@ categories = ["tools", "git"] description = "show function history from git" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["parallel"] +default = ["parallel", "unstable"] parallel = ["dep:rayon"] c_lang = [] +unstable = ["dep:gosyn", "dep:javaparser"] [dependencies] chrono = "0.4.22" ra_ap_syntax = "0.0.133" rayon = { version = "1.5.1", optional = true } rustpython-parser = "0.1.2" +lib-ruby-parser = "3.0.12" +gosyn = {version = "0.1.1", optional = true} +javaparser = {git = "https://github.com/tanin47/javaparser.rs", optional = true} \ No newline at end of file diff --git a/git-function-history-lib/README.md b/git-function-history-lib/README.md index b7273272..6481f3e7 100644 --- a/git-function-history-lib/README.md +++ b/git-function-history-lib/README.md @@ -11,4 +11,5 @@ Use the latest [crates.io](https://crates.io/crates/git_function_history) by put - parallel: use rayon to parallelize the git log search - --no-default-features: disable parallelism -- c-lang: adds support c (requires you to have a c compiler installed) (see the [c-lib]() docs for more information) \ No newline at end of file +- c-lang: adds support c (requires you to have a c compiler installed) (see the [c-lib]() docs for more information) +- unstable: enable some parsers that require nightly rust so run `cargo +nightly` to use them \ No newline at end of file diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs new file mode 100644 index 00000000..eea18b34 --- /dev/null +++ b/git-function-history-lib/src/languages/go.rs @@ -0,0 +1,217 @@ +use std::{error::Error, fmt, collections::HashMap}; + +use crate::impl_function_trait; + +use super::FunctionTrait; + +#[derive(Debug, Clone)] +pub struct GoFunction { + pub(crate) name: String, + pub(crate) body: String, + pub(crate) parameters: Vec, + pub(crate) parent: Vec, + pub(crate) returns: Option, + pub(crate) lines: (usize, usize), +} + +impl GoFunction { + pub fn new( + name: String, + body: String, + parameters: Vec, + parent: Vec, + returns: Option, + lines: (usize, usize), + ) -> Self { + Self { + name, + body, + parameters, + parent, + returns, + lines, + } + } +} + +impl fmt::Display for GoFunction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.name)?; + if !self.parameters.is_empty() { + write!(f, "(")?; + for (i, param) in self.parameters.iter().enumerate() { + if i != 0 { + write!(f, ", ")?; + } + write!(f, "{}", param)?; + } + write!(f, ")")?; + } + if let Some(ret) = &self.returns { + write!(f, " -> {}", ret)?; + } + Ok(()) + } +} + +#[derive(Debug, Clone)] +pub struct ParentFunction { + pub(crate) name: String, + pub(crate) top: String, + pub(crate) returns: Option, + pub(crate) parameters: Vec, + pub(crate) lines: (usize, usize), +} + +impl ParentFunction { + pub fn new( + name: String, + top: String, + returns: Option, + parameters: Vec, + lines: (usize, usize), + ) -> Self { + Self { + name, + top, + returns, + parameters, + lines, + } + } +} + + +impl FunctionTrait for GoFunction { + impl_function_trait!(GoFunction); + + fn get_bottoms(&self) -> Vec { + let mut bottoms = Vec::new(); + for parent in &self.parent { + bottoms.push(parent.top.clone()); + } + bottoms + } + + fn get_tops(&self) -> Vec { + let mut tops = Vec::new(); + for parent in &self.parent { + tops.push(parent.top.clone()); + } + tops + } + + fn get_total_lines(&self) -> (usize, usize) { + let mut start = self.lines.0; + let mut end = self.lines.1; + for parent in &self.parent { + if parent.lines.0 < start { + start = parent.lines.0; + } + if parent.lines.1 > end { + end = parent.lines.1; + } + } + (start, end) + } +} + + +pub(crate) fn find_function_in_file( + file_contents: &str, + name: &str, +) -> Result, Box> { + let mut starts = file_contents + .match_indices('\n') + .map(|x| x.0) + .collect::>(); + starts.push(0); + starts.sort_unstable(); + let map = starts + .iter() + .enumerate() + .collect::>(); + println!("map: {:?}", map); + let parsed_file = gosyn::parse_source(file_contents).map_err(|e| format!("{:?}", e))?.decl; + Ok(parsed_file + .into_iter() + .filter_map(|decl| match decl { + gosyn::ast::Declaration::Function(func) => { + if func.name.name == name { + println!("{}", func.typ.pos); + + let mut lines = (func.name.pos, func.body.as_ref().unwrap().pos.1); + for i in &func.docs { + if i.pos < lines.0 { + lines.0 = i.pos; + } + } + let body = file_contents[lines.0..lines.1+1].to_string(); + println!("body: {}", body); + for i in 0..func.name.pos { + if file_contents.chars().nth(i).unwrap() == '\n' { + lines.0 = i + 1; + break; + } + } + for i in func.body.as_ref().unwrap().pos.1..file_contents.len() { + if file_contents.chars().nth(i).unwrap() == '\n' { + lines.1 = i; + break; + } + } + + + lines.0 = *map.keys().find(|x| **x >= lines.0).unwrap(); + // lines.1 = *map.keys().rfind(|x| **x >= lines.1).unwrap(); + + let parameters = func.typ.params.list.iter().map(|p| &p.tag.as_ref().unwrap().value).map(|x| x.to_string()).collect(); + let returns = Some(func.typ.result.list.iter().map(|p| p.name.iter().map(|x| &x.clone().name).map(|x| x.to_string()).collect::()).collect()).filter(|x: &String| !x.is_empty()); + let parent = vec![]; + Some(GoFunction::new( + func.name.name, + body, + parameters, + parent, + returns, + lines, + )) + } else { + None + } + + + } + _ => None, + }) + .collect::>()) + + +} + +#[cfg(test)] +mod t { + use super::*; + + #[test] + fn test_go() { + let file_contents = r#" +package main +import "fmt" +//g + +func mains() { + + fmt.Println("Hello, World!") + +} "#; + let functions = find_function_in_file(file_contents, "mains").unwrap(); + println!("{:#?}", functions[0]); + assert_eq!(functions.len(), 1); + assert_eq!(functions[0].name, "main"); + assert_eq!(functions[0].parameters.len(), 0); + assert_eq!(functions[0].parent.len(), 0); + assert_eq!(functions[0].returns, None); + assert_eq!(functions[0].lines, (3, 5)); + } +} \ No newline at end of file diff --git a/git-function-history-lib/src/languages/java.rs b/git-function-history-lib/src/languages/java.rs new file mode 100644 index 00000000..e69de29b diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 2dbeb19f..a9c9edda 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -3,7 +3,7 @@ use std::{ error::Error, fmt::{self, Display}, }; - +// TODO: lisp/scheme js go(https://docs.rs/gosyn/latest/gosyn/) ruby(https://docs.rs/lib-ruby-parser/latest/lib_ruby_parser/) java?(https://github.com/tanin47/javaparser.rs) php?(https://docs.rs/tagua-parser/0.1.0/tagua_parser/) use self::{python::PythonFunction, rust::RustFunction}; #[cfg(feature = "c_lang")] @@ -59,6 +59,12 @@ impl fmt::Display for Language { pub mod c; pub mod python; pub mod rust; +pub mod ruby; +#[cfg(feature = "unstable")] +pub mod go; +#[cfg(feature = "unstable")] +pub mod java; + pub trait FunctionTrait: fmt::Debug + fmt::Display { fn get_tops(&self) -> Vec; diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs new file mode 100644 index 00000000..e69de29b From d58c939bdb3fe4bfd14adb7673f85035603fd296 Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Fri, 14 Oct 2022 00:01:47 -0400 Subject: [PATCH 050/172] not on by deafault --- git-function-history-lib/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 72a5e91b..6f73878a 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -9,7 +9,7 @@ categories = ["tools", "git"] description = "show function history from git" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["parallel", "unstable"] +default = ["parallel"] parallel = ["dep:rayon"] c_lang = [] unstable = ["dep:gosyn", "dep:javaparser"] From 669d7e1f92158a90e2ecf24f7b9be88f631204cd Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Fri, 14 Oct 2022 03:21:53 -0400 Subject: [PATCH 051/172] sprinkling some inlines --- git-function-history-lib/src/languages/c.rs | 2 +- git-function-history-lib/src/languages/python.rs | 4 ++-- git-function-history-lib/src/languages/rust.rs | 8 ++++---- git-function-history-lib/src/lib.rs | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/git-function-history-lib/src/languages/c.rs b/git-function-history-lib/src/languages/c.rs index 091fcd0f..4a7183d5 100644 --- a/git-function-history-lib/src/languages/c.rs +++ b/git-function-history-lib/src/languages/c.rs @@ -63,7 +63,7 @@ pub struct ParentFunction { pub(crate) parameters: Vec, pub(crate) returns: Option, } - +#[inline] pub(crate) fn find_function_in_file( file_contents: &str, name: &str, diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index e3eb9ebf..9111bde2 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -137,7 +137,7 @@ pub(crate) fn find_function_in_file( } Ok(new) } - +#[inline] fn fun_name1( body: Vec>, functions: &mut Vec<(StatementType, (Location, Location))>, @@ -155,7 +155,7 @@ fn fun_name1( ); } } - +#[inline] fn fun_name( other_last_found_fn: &mut Option<(StatementType, Location)>, last_found_fn: &mut Option<(StatementType, Location)>, diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index cc51e8e3..29a155a9 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -353,7 +353,7 @@ pub(crate) fn find_function_in_file( } Ok(hist) } - +#[inline] fn get_function_asts(name: &str, file: &str, functions: &mut Vec) { let parsed_file = SourceFile::parse(file).tree(); parsed_file @@ -363,7 +363,7 @@ fn get_function_asts(name: &str, file: &str, functions: &mut Vec) { .filter(|function| function.name().unwrap().text() == name) .for_each(|function| functions.push(function)); } - +#[inline] fn get_stuff( block: &T, file: &str, @@ -433,7 +433,7 @@ fn get_stuff( (starts, end_line), ) } - +#[inline] fn get_genrerics_and_lifetime(block: &T) -> (Vec, Vec) { // TODO: map trait bounds from where clauses to the generics and also use type_or_const_params match block.generic_param_list() { @@ -448,7 +448,7 @@ fn get_genrerics_and_lifetime(block: &T) -> (Vec, V ), } } - +#[inline] fn get_doc_comments_and_attrs(block: &T) -> (Vec, Vec) { ( block diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index b8d6ae2b..aae748c8 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -309,7 +309,7 @@ macro_rules! get_function_history { ) }}; } - +#[inline] /// List all the commits date in the git history (in rfc2822 format). pub fn get_git_dates() -> Result, Box> { let output = Command::new("git") @@ -322,7 +322,7 @@ pub fn get_git_dates() -> Result, Box> { .collect::>(); Ok(output) } - +#[inline] /// List all the commit hashes in the git history. pub fn get_git_commit_hashes() -> Result, Box> { let output = Command::new("git").args(["log", "--pretty=%H"]).output()?; @@ -333,7 +333,7 @@ pub fn get_git_commit_hashes() -> Result, Box> { .collect::>(); Ok(output) } - +#[inline] fn find_file_in_commit(commit: &str, file_path: &str) -> Result> { let commit_history = Command::new("git") .args(format!("show {}:{}", commit, file_path).split(' ')) From 1051747d0d4d123b0f212d66246232a0e9e3a8cf Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Fri, 14 Oct 2022 03:37:20 -0400 Subject: [PATCH 052/172] fixed bug whetere fromatwithcontext was being fed the wrong data, also cargo fmt --- git-function-history-lib/src/languages/go.rs | 104 ++++++++++-------- .../src/languages/java.rs | 1 + git-function-history-lib/src/languages/mod.rs | 7 +- .../src/languages/python.rs | 2 +- .../src/languages/ruby.rs | 1 + .../src/languages/rust.rs | 2 +- 6 files changed, 67 insertions(+), 50 deletions(-) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index eea18b34..6b437a27 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -1,4 +1,4 @@ -use std::{error::Error, fmt, collections::HashMap}; +use std::{collections::HashMap, error::Error, fmt}; use crate::impl_function_trait; @@ -81,7 +81,6 @@ impl ParentFunction { } } - impl FunctionTrait for GoFunction { impl_function_trait!(GoFunction); @@ -116,7 +115,6 @@ impl FunctionTrait for GoFunction { } } - pub(crate) fn find_function_in_file( file_contents: &str, name: &str, @@ -131,62 +129,80 @@ pub(crate) fn find_function_in_file( .iter() .enumerate() .collect::>(); - println!("map: {:?}", map); - let parsed_file = gosyn::parse_source(file_contents).map_err(|e| format!("{:?}", e))?.decl; - Ok(parsed_file + println!("map: {:?}", map); + let parsed_file = gosyn::parse_source(file_contents) + .map_err(|e| format!("{:?}", e))? + .decl; + Ok(parsed_file .into_iter() .filter_map(|decl| match decl { gosyn::ast::Declaration::Function(func) => { if func.name.name == name { - println!("{}", func.typ.pos); + println!("{}", func.typ.pos); - let mut lines = (func.name.pos, func.body.as_ref().unwrap().pos.1); - for i in &func.docs { - if i.pos < lines.0 { - lines.0 = i.pos; + let mut lines = (func.name.pos, func.body.as_ref().unwrap().pos.1); + for i in &func.docs { + if i.pos < lines.0 { + lines.0 = i.pos; + } } - } - let body = file_contents[lines.0..lines.1+1].to_string(); - println!("body: {}", body); - for i in 0..func.name.pos { - if file_contents.chars().nth(i).unwrap() == '\n' { - lines.0 = i + 1; - break; + let body = file_contents[lines.0..lines.1 + 1].to_string(); + println!("body: {}", body); + for i in 0..func.name.pos { + if file_contents.chars().nth(i).unwrap() == '\n' { + lines.0 = i + 1; + break; + } } - } - for i in func.body.as_ref().unwrap().pos.1..file_contents.len() { - if file_contents.chars().nth(i).unwrap() == '\n' { - lines.1 = i; - break; + for i in func.body.as_ref().unwrap().pos.1..file_contents.len() { + if file_contents.chars().nth(i).unwrap() == '\n' { + lines.1 = i; + break; + } } - } - - lines.0 = *map.keys().find(|x| **x >= lines.0).unwrap(); - // lines.1 = *map.keys().rfind(|x| **x >= lines.1).unwrap(); - - let parameters = func.typ.params.list.iter().map(|p| &p.tag.as_ref().unwrap().value).map(|x| x.to_string()).collect(); - let returns = Some(func.typ.result.list.iter().map(|p| p.name.iter().map(|x| &x.clone().name).map(|x| x.to_string()).collect::()).collect()).filter(|x: &String| !x.is_empty()); - let parent = vec![]; - Some(GoFunction::new( - func.name.name, - body, - parameters, - parent, - returns, - lines, - )) + lines.0 = *map.keys().find(|x| **x >= lines.0).unwrap(); + // lines.1 = *map.keys().rfind(|x| **x >= lines.1).unwrap(); + + let parameters = func + .typ + .params + .list + .iter() + .map(|p| &p.tag.as_ref().unwrap().value) + .map(|x| x.to_string()) + .collect(); + let returns = Some( + func.typ + .result + .list + .iter() + .map(|p| { + p.name + .iter() + .map(|x| &x.clone().name) + .map(|x| x.to_string()) + .collect::() + }) + .collect(), + ) + .filter(|x: &String| !x.is_empty()); + let parent = vec![]; + Some(GoFunction::new( + func.name.name, + body, + parameters, + parent, + returns, + lines, + )) } else { None } - - } _ => None, }) .collect::>()) - - } #[cfg(test)] @@ -214,4 +230,4 @@ func mains() { assert_eq!(functions[0].returns, None); assert_eq!(functions[0].lines, (3, 5)); } -} \ No newline at end of file +} diff --git a/git-function-history-lib/src/languages/java.rs b/git-function-history-lib/src/languages/java.rs index e69de29b..8b137891 100644 --- a/git-function-history-lib/src/languages/java.rs +++ b/git-function-history-lib/src/languages/java.rs @@ -0,0 +1 @@ + diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index a9c9edda..fec464df 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -57,14 +57,13 @@ impl fmt::Display for Language { } #[cfg(feature = "c_lang")] pub mod c; -pub mod python; -pub mod rust; -pub mod ruby; #[cfg(feature = "unstable")] pub mod go; #[cfg(feature = "unstable")] pub mod java; - +pub mod python; +pub mod ruby; +pub mod rust; pub trait FunctionTrait: fmt::Debug + fmt::Display { fn get_tops(&self) -> Vec; diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 9111bde2..c9ae5b61 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -322,7 +322,7 @@ impl FunctionTrait for PythonFunction { fn get_total_lines(&self) -> (usize, usize) { match &self.class { - Some(block) => (block.lines.0, self.lines.1), + Some(block) => (block.lines), None => { let mut start = self.lines.0; let mut end = self.lines.1; diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index e69de29b..8b137891 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -0,0 +1 @@ + diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 29a155a9..998ca0c8 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -522,7 +522,7 @@ impl FunctionTrait for RustFunction { fn get_total_lines(&self) -> (usize, usize) { match &self.block { - Some(block) => (block.lines.0, self.lines.1), + Some(block) => (block.lines.0, block.lines.1), None => { let mut start = self.lines.0; let mut end = self.lines.1; From 398d32da0451fd7791abb7b3d1a47f06b67190c7 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Fri, 14 Oct 2022 17:29:43 -0400 Subject: [PATCH 053/172] go function partialy working with unstable --- git-function-history-lib/src/languages/go.rs | 71 ++++++++++++-------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index 6b437a27..7be1704e 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -119,17 +119,7 @@ pub(crate) fn find_function_in_file( file_contents: &str, name: &str, ) -> Result, Box> { - let mut starts = file_contents - .match_indices('\n') - .map(|x| x.0) - .collect::>(); - starts.push(0); - starts.sort_unstable(); - let map = starts - .iter() - .enumerate() - .collect::>(); - println!("map: {:?}", map); + // TODO: use expect() instead of unwrap() for better error handling let parsed_file = gosyn::parse_source(file_contents) .map_err(|e| format!("{:?}", e))? .decl; @@ -138,32 +128,47 @@ pub(crate) fn find_function_in_file( .filter_map(|decl| match decl { gosyn::ast::Declaration::Function(func) => { if func.name.name == name { - println!("{}", func.typ.pos); let mut lines = (func.name.pos, func.body.as_ref().unwrap().pos.1); + match func.recv { + Some(recv) => { + lines.0 = recv.pos(); + } + None => {} + } + lines.0 =file_contents[..lines.0].rfind("func").unwrap(); for i in &func.docs { if i.pos < lines.0 { lines.0 = i.pos; } } let body = file_contents[lines.0..lines.1 + 1].to_string(); - println!("body: {}", body); - for i in 0..func.name.pos { - if file_contents.chars().nth(i).unwrap() == '\n' { - lines.0 = i + 1; - break; + let mut start_line = 0; + for i in file_contents.chars().enumerate() { + if i.1 == '\n' { + if i.0 > lines.0 { + lines.0 = i.0; + break; + } + start_line += 1; } + } - for i in func.body.as_ref().unwrap().pos.1..file_contents.len() { - if file_contents.chars().nth(i).unwrap() == '\n' { - lines.1 = i; - break; + let mut end_line = 0; + for i in file_contents.chars().enumerate() { + if i.1 == '\n' { + if i.0 > lines.1 { + lines.1 = i.0; + break; + } + end_line += 1; } } - lines.0 = *map.keys().find(|x| **x >= lines.0).unwrap(); - // lines.1 = *map.keys().rfind(|x| **x >= lines.1).unwrap(); + lines.0 = start_line; + lines.1 = end_line; + println!("lines: {:?}-", lines); let parameters = func .typ .params @@ -187,6 +192,7 @@ pub(crate) fn find_function_in_file( .collect(), ) .filter(|x: &String| !x.is_empty()); + // TODO: get parent functions let parent = vec![]; Some(GoFunction::new( func.name.name, @@ -214,20 +220,27 @@ mod t { let file_contents = r#" package main import "fmt" -//g -func mains() { + +func (s *Selection) mains() { fmt.Println("Hello, World!") -} "#; +} + +func mains() { + fmt.Println("Hello, World!") +} + + +"#; let functions = find_function_in_file(file_contents, "mains").unwrap(); println!("{:#?}", functions[0]); - assert_eq!(functions.len(), 1); - assert_eq!(functions[0].name, "main"); + assert_eq!(functions.len(), 2); + assert_eq!(functions[0].name, "mains"); assert_eq!(functions[0].parameters.len(), 0); assert_eq!(functions[0].parent.len(), 0); assert_eq!(functions[0].returns, None); - assert_eq!(functions[0].lines, (3, 5)); + assert_eq!(functions[0].lines, (5, 9)); } } From 88e6a8429ba26c4f42e092fc9460e3aeeebefe6d Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Wed, 19 Oct 2022 14:01:07 -0400 Subject: [PATCH 054/172] go function cant have parents moved some unwraps to expects --- git-function-history-lib/src/languages/go.rs | 86 ++++++-------------- 1 file changed, 25 insertions(+), 61 deletions(-) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index 7be1704e..174f9de5 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -9,7 +9,6 @@ pub struct GoFunction { pub(crate) name: String, pub(crate) body: String, pub(crate) parameters: Vec, - pub(crate) parent: Vec, pub(crate) returns: Option, pub(crate) lines: (usize, usize), } @@ -19,7 +18,6 @@ impl GoFunction { name: String, body: String, parameters: Vec, - parent: Vec, returns: Option, lines: (usize, usize), ) -> Self { @@ -27,7 +25,6 @@ impl GoFunction { name, body, parameters, - parent, returns, lines, } @@ -54,63 +51,20 @@ impl fmt::Display for GoFunction { } } -#[derive(Debug, Clone)] -pub struct ParentFunction { - pub(crate) name: String, - pub(crate) top: String, - pub(crate) returns: Option, - pub(crate) parameters: Vec, - pub(crate) lines: (usize, usize), -} - -impl ParentFunction { - pub fn new( - name: String, - top: String, - returns: Option, - parameters: Vec, - lines: (usize, usize), - ) -> Self { - Self { - name, - top, - returns, - parameters, - lines, - } - } -} - impl FunctionTrait for GoFunction { impl_function_trait!(GoFunction); fn get_bottoms(&self) -> Vec { - let mut bottoms = Vec::new(); - for parent in &self.parent { - bottoms.push(parent.top.clone()); - } - bottoms + vec![] } fn get_tops(&self) -> Vec { - let mut tops = Vec::new(); - for parent in &self.parent { - tops.push(parent.top.clone()); - } - tops + vec![] } fn get_total_lines(&self) -> (usize, usize) { - let mut start = self.lines.0; - let mut end = self.lines.1; - for parent in &self.parent { - if parent.lines.0 < start { - start = parent.lines.0; - } - if parent.lines.1 > end { - end = parent.lines.1; - } - } + let start = self.lines.0; + let end = self.lines.1; (start, end) } } @@ -119,7 +73,7 @@ pub(crate) fn find_function_in_file( file_contents: &str, name: &str, ) -> Result, Box> { - // TODO: use expect() instead of unwrap() for better error handling + // TODO: progate errors back in clusre intead of paicking with excpet let parsed_file = gosyn::parse_source(file_contents) .map_err(|e| format!("{:?}", e))? .decl; @@ -128,15 +82,23 @@ pub(crate) fn find_function_in_file( .filter_map(|decl| match decl { gosyn::ast::Declaration::Function(func) => { if func.name.name == name { - - let mut lines = (func.name.pos, func.body.as_ref().unwrap().pos.1); + let mut lines = ( + func.name.pos, + func.body + .as_ref() + .expect("no body found for function") + .pos + .1, + ); match func.recv { Some(recv) => { lines.0 = recv.pos(); } None => {} } - lines.0 =file_contents[..lines.0].rfind("func").unwrap(); + lines.0 = file_contents[..lines.0] + .rfind("func") + .expect("could not find 'func' keyword before function"); for i in &func.docs { if i.pos < lines.0 { lines.0 = i.pos; @@ -152,7 +114,6 @@ pub(crate) fn find_function_in_file( } start_line += 1; } - } let mut end_line = 0; for i in file_contents.chars().enumerate() { @@ -167,14 +128,12 @@ pub(crate) fn find_function_in_file( lines.0 = start_line; lines.1 = end_line; - - println!("lines: {:?}-", lines); let parameters = func .typ .params .list .iter() - .map(|p| &p.tag.as_ref().unwrap().value) + .map(|p| &p.tag.as_ref().expect("uknown plz report bug idk").value) .map(|x| x.to_string()) .collect(); let returns = Some( @@ -193,12 +152,10 @@ pub(crate) fn find_function_in_file( ) .filter(|x: &String| !x.is_empty()); // TODO: get parent functions - let parent = vec![]; Some(GoFunction::new( func.name.name, body, parameters, - parent, returns, lines, )) @@ -232,6 +189,14 @@ func mains() { fmt.Println("Hello, World!") } +func p() { + + // func mains() { + + // } + // mains(); +} + "#; let functions = find_function_in_file(file_contents, "mains").unwrap(); @@ -239,7 +204,6 @@ func mains() { assert_eq!(functions.len(), 2); assert_eq!(functions[0].name, "mains"); assert_eq!(functions[0].parameters.len(), 0); - assert_eq!(functions[0].parent.len(), 0); assert_eq!(functions[0].returns, None); assert_eq!(functions[0].lines, (5, 9)); } From c21ae7abc9e2ae1e6e83d03554110dbae6191d19 Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Wed, 19 Oct 2022 14:26:39 -0400 Subject: [PATCH 055/172] go support is mostly done --- cargo-function-history/Cargo.toml | 1 + cargo-function-history/src/app/mod.rs | 181 +----------------- function_history_backend_thread/Cargo.toml | 1 + git-function-history-gui/Cargo.toml | 1 + git-function-history-gui/src/lib.rs | 2 + git-function-history-lib/src/languages/go.rs | 54 ++---- git-function-history-lib/src/languages/mod.rs | 17 ++ .../src/languages/python.rs | 2 +- git-function-history-lib/src/lib.rs | 21 ++ .../src/test_functions.go | 14 ++ git-function-history-lib/src/types.rs | 18 ++ 11 files changed, 96 insertions(+), 216 deletions(-) create mode 100644 git-function-history-lib/src/test_functions.go diff --git a/cargo-function-history/Cargo.toml b/cargo-function-history/Cargo.toml index 28d4c1cd..0faa03ae 100644 --- a/cargo-function-history/Cargo.toml +++ b/cargo-function-history/Cargo.toml @@ -15,6 +15,7 @@ default = ["parallel"] parallel = ["git_function_history/parallel", "function_history_backend_thread/parallel"] not-parallel = [] c_lang = ["function_history_backend_thread/c_lang", "git_function_history/c_lang"] +unstable = ["function_history_backend_thread/unstable", "git_function_history/unstable"] [dependencies] git_function_history = { path = "../git-function-history-lib", version = "0.6.2", default-features = false} diff --git a/cargo-function-history/src/app/mod.rs b/cargo-function-history/src/app/mod.rs index dfc03e9d..b60ecae1 100644 --- a/cargo-function-history/src/app/mod.rs +++ b/cargo-function-history/src/app/mod.rs @@ -316,185 +316,6 @@ impl App { let mut file = FileFilterType::None; let mut filter = Filter::None; let mut lang = Language::All; - // let search = match iter.next() { - // None => { - // // if there is no next arg then we are searching for a function - // // with the given name - // Some(FullCommand::Search( - // name.to_string(), - // FileFilterType::None, - // Filter::None, - // Language::Rust, - // )) - // } - // Some(thing) => match thing { - // "relative" | "absolute" => { - // let file_type = match iter.next() { - // Some(filter) => match thing { - // "relative" => { - // FileFilterType::Relative(filter.to_string()) - // } - // "absolute" => { - // FileFilterType::Absolute(filter.to_string()) - // } - // _ => FileFilterType::None, - // }, - // None => { - // self.status = - // Status::Error("No filter given".to_string()); - // return; - // } - // }; - // let filter = match iter.next() { - // Some(filter) => match filter { - // "date" => { - // let date = iter.next(); - // match date { - // Some(date) => { - // let date = date.replace('_', " "); - // Filter::Date(date) - // } - // None => { - // self.status = Status::Error( - // "No date given".to_string(), - // ); - // return; - // } - // } - // } - // "commit" => { - // let commit = iter.next(); - // match commit { - // Some(commit) => { - // Filter::CommitHash(commit.to_string()) - // } - // None => { - // self.status = Status::Error( - // "No commit given".to_string(), - // ); - // return; - // } - // } - // } - // "date range" => { - // let start = iter.next(); - // let end = iter.next(); - // match (start, end) { - // (Some(start), Some(end)) => { - // let start = start.replace('_', " "); - // let end = end.replace('_', " "); - // Filter::DateRange(start, end) - // } - // _ => { - // self.status = Status::Error( - // "No date range given".to_string(), - // ); - // return; - // } - // } - // } - // _ => { - // self.status = - // Status::Error("No filter given".to_string()); - // return; - // } - // }, - // None => Filter::None, - // }; - // Some(FullCommand::Search( - // name.to_string(), - // file_type, - // filter, - // Language::Rust, - // )) - // } - // "date" | "commit" | "date range" => { - // let filter = match thing { - // "date" => { - // let date = iter.next(); - // match date { - // Some(date) => Filter::Date(date.to_string()), - // None => { - // self.status = - // Status::Error("No date given".to_string()); - // return; - // } - // } - // } - // "commit" => { - // let commit = iter.next(); - // match commit { - // Some(commit) => { - // Filter::CommitHash(commit.to_string()) - // } - // None => { - // self.status = Status::Error( - // "No commit given".to_string(), - // ); - // return; - // } - // } - // } - // "date range" => { - // let start = iter.next(); - // let end = iter.next(); - // match (start, end) { - // (Some(start), Some(end)) => Filter::DateRange( - // start.to_string(), - // end.to_string(), - // ), - // _ => { - // self.status = Status::Error( - // "No date range given".to_string(), - // ); - // return; - // } - // } - // } - // _ => Filter::None, - // }; - // Some(FullCommand::Search( - // name.to_string(), - // FileFilterType::None, - // filter, - // Language::Rust, - // )) - // } - // "language" => { - // let language = iter.next(); - // match language { - // Some(language) => { - // let language = match language { - // "rust" => Language::Rust, - // "python" => Language::Python, - // "c" => Language::C, - // _ => { - // self.status = Status::Error( - // "Invalid language".to_string(), - // ); - // return; - // } - // }; - // Some(FullCommand::Search( - // name.to_string(), - // FileFilterType::None, - // Filter::None, - // language, - // )) - // } - // None => { - // self.status = - // Status::Error("No language given".to_string()); - // return; - // } - // } - // } - // _ => { - // self.status = Status::Error("Invalid file type".to_string()); - // None - // } - // }, - // }; for i in iter.collect::>().windows(2) { match i { ["relative", filepath] => { @@ -518,6 +339,8 @@ impl App { &"python" => Language::Python, #[cfg(feature = "c_lang")] &"c" => Language::C, + #[cfg(feature = "unstable")] + &"go" => Language::Go, _ => { self.status = Status::Error("Invalid language".to_string()); diff --git a/function_history_backend_thread/Cargo.toml b/function_history_backend_thread/Cargo.toml index a19e578a..d183d728 100644 --- a/function_history_backend_thread/Cargo.toml +++ b/function_history_backend_thread/Cargo.toml @@ -16,6 +16,7 @@ default = ["parallel"] parallel = ["git_function_history/parallel"] not-parallel = [] c_lang = ["git_function_history/c_lang"] +unstable = ["git_function_history/unstable"] [dependencies] git_function_history = { path = "../git-function-history-lib", version = "0.6.2", default-features = false} diff --git a/git-function-history-gui/Cargo.toml b/git-function-history-gui/Cargo.toml index 1d905c0c..0d5f1bee 100644 --- a/git-function-history-gui/Cargo.toml +++ b/git-function-history-gui/Cargo.toml @@ -15,6 +15,7 @@ default = ["parallel"] parallel = ["git_function_history/parallel", "function_history_backend_thread/parallel"] not-parallel = [] c_lang = ["git_function_history/c_lang", "function_history_backend_thread/c_lang"] +unstable = ["git_function_history/unstable", "function_history_backend_thread/unstable"] [dependencies] eframe = {version = "0.19.0", features = ["dark-light"]} diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index 9c8e0344..b387fcd2 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -600,6 +600,8 @@ impl eframe::App for MyEguiApp { Language::Python => "Python", Language::All => "Language", + #[cfg(feature = "unstable")] + Language::Go => "Go", }; egui::ComboBox::from_id_source("search_language_combo_box") .selected_text(text) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index 174f9de5..b276f58b 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -168,43 +168,25 @@ pub(crate) fn find_function_in_file( .collect::>()) } -#[cfg(test)] -mod t { - use super::*; - - #[test] - fn test_go() { - let file_contents = r#" -package main -import "fmt" - - -func (s *Selection) mains() { - - fmt.Println("Hello, World!") +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Filter { + FunctionWithParameter(String), + FunctionWithReturnType(String), + FunctionInLines(usize, usize), } -func mains() { - fmt.Println("Hello, World!") -} - -func p() { - - // func mains() { - - // } - // mains(); -} - - -"#; - let functions = find_function_in_file(file_contents, "mains").unwrap(); - println!("{:#?}", functions[0]); - assert_eq!(functions.len(), 2); - assert_eq!(functions[0].name, "mains"); - assert_eq!(functions[0].parameters.len(), 0); - assert_eq!(functions[0].returns, None); - assert_eq!(functions[0].lines, (5, 9)); +impl Filter { + pub fn matches(&self, func: &GoFunction) -> bool { + match self { + Filter::FunctionWithParameter(param) => { + func.parameters.iter().any(|x| x.contains(param)) + } + Filter::FunctionWithReturnType(ret) => func.returns.as_ref().map(|x| x.contains(ret)).unwrap_or(false), + Filter::FunctionInLines(start, end) => { + let (s, e) = func.get_total_lines(); + s >= *start && e <= *end + } + } } -} +} \ No newline at end of file diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index fec464df..cd04a6fe 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -8,6 +8,9 @@ use self::{python::PythonFunction, rust::RustFunction}; #[cfg(feature = "c_lang")] use self::c::CFunction; + +#[cfg(feature = "unstable")] +use go::GoFunction; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Language { /// The python language @@ -17,6 +20,9 @@ pub enum Language { #[cfg(feature = "c_lang")] /// c language C, + #[cfg(feature = "unstable")] + /// The go language + Go, /// all available languages All, } @@ -29,6 +35,9 @@ pub enum LanguageFilter { #[cfg(feature = "c_lang")] /// c filter C(c::Filter), + #[cfg(feature = "unstable")] + /// go filter + Go(go::Filter), } impl Language { @@ -38,6 +47,8 @@ impl Language { "rust" => Ok(Self::Rust), #[cfg(feature = "c_lang")] "c" => Ok(Self::C), + #[cfg(feature = "unstable")] + "go" => Ok(Self::Go), "all" => Ok(Self::All), _ => Err(format!("Unknown language: {}", s))?, } @@ -51,6 +62,8 @@ impl fmt::Display for Language { Self::Rust => write!(f, "rust"), #[cfg(feature = "c_lang")] Self::C => write!(f, "c"), + #[cfg(feature = "unstable")] + Self::Go => write!(f, "go"), Self::All => write!(f, "all"), } } @@ -239,6 +252,8 @@ make_file!(PythonFile, PythonFunction, Python); make_file!(RustFile, RustFunction, Rust); #[cfg(feature = "c_lang")] make_file!(CFile, CFunction, C); +#[cfg(feature = "unstable")] +make_file!(GoFile, GoFunction, Go); use std::path::MAIN_SEPARATOR; // make macro that auto genertes the test parse__file_time macro_rules! make_file_time_test { @@ -266,4 +281,6 @@ mod lang_tests { make_file_time_test!(rust_parses, rs, rust); #[cfg(feature = "c_lang")] make_file_time_test!(c_parses, c, c); + #[cfg(feature = "unstable")] + make_file_time_test!(go_parses, go, go); } diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index c9ae5b61..4e864d56 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -322,7 +322,7 @@ impl FunctionTrait for PythonFunction { fn get_total_lines(&self) -> (usize, usize) { match &self.class { - Some(block) => (block.lines), + Some(block) => block.lines, None => { let mut start = self.lines.0; let mut end = self.lines.1; diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index aae748c8..252bfd4f 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -27,6 +27,8 @@ pub use types::FileType; #[cfg(feature = "c_lang")] use languages::CFile; +#[cfg(feature = "unstable")] +use languages::GoFile; use std::{error::Error, process::Command}; pub use types::{Commit, FunctionHistory}; @@ -197,6 +199,12 @@ pub fn get_function_history( Err(format!("file is not a c file: {}", path))?; } } + #[cfg(feature = "unstable")] + Language::Go => { + if !path.ends_with(".go") { + Err(format!("file is not a go file: {}", path))?; + } + } Language::Python => { if !path.ends_with(".py") { Err(format!("file is not a python file: {}", path))?; @@ -384,6 +392,12 @@ fn find_function_in_commit_with_filetype( files.push(file); } } + #[cfg(feature = "unstable")] + Language::Go => { + if file.ends_with(".go") { + files.push(file); + } + } Language::Python => { if file.ends_with(".py") { files.push(file); @@ -400,6 +414,8 @@ fn find_function_in_commit_with_filetype( // TODO: use cfg!() macro to check if c_lang is enabled || file.ends_with(".c") || file.ends_with(".h") + // TODO: use cfg!() macro to check if unstable is enabled + || file.ends_with(".go") { files.push(file); } @@ -442,6 +458,11 @@ fn find_function_in_file_with_commit( let functions = languages::c::find_function_in_file(&fc, name)?; Ok(FileType::C(CFile::new(file_path.to_string(), functions))) } + #[cfg(feature = "unstable")] + Language::Go => { + let functions = languages::go::find_function_in_file(&fc, name)?; + Ok(FileType::Go(GoFile::new(file_path.to_string(), functions))) + } Language::Python => { let functions = languages::python::find_function_in_file(&fc, name)?; Ok(FileType::Python(PythonFile::new( diff --git a/git-function-history-lib/src/test_functions.go b/git-function-history-lib/src/test_functions.go new file mode 100644 index 00000000..84000d2a --- /dev/null +++ b/git-function-history-lib/src/test_functions.go @@ -0,0 +1,14 @@ +package main + +import ( + "fmt" + "os" +) + +func main() { + fmt.Println("Hello World!") +} + +func empty_test() { + fmt.Println("Hello World!") +} \ No newline at end of file diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index a95cb2d0..06070b12 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -16,12 +16,17 @@ use crate::{ #[cfg(feature = "c_lang")] use crate::languages::CFile; +#[cfg(feature = "unstable")] +use crate::languages::GoFile; + #[derive(Debug, Clone)] pub enum FileType { Rust(RustFile), Python(PythonFile), #[cfg(feature = "c_lang")] C(CFile), + #[cfg(feature = "unstable")] + Go(GoFile), } impl FileTrait for FileType { @@ -31,6 +36,8 @@ impl FileTrait for FileType { Self::Python(file) => file.get_file_name(), #[cfg(feature = "c_lang")] FileType::C(file) => file.get_file_name(), + #[cfg(feature = "unstable")] + FileType::Go(file) => file.get_file_name(), } } fn get_functions(&self) -> Vec> { @@ -39,6 +46,8 @@ impl FileTrait for FileType { Self::Python(file) => file.get_functions(), #[cfg(feature = "c_lang")] FileType::C(file) => file.get_functions(), + #[cfg(feature = "unstable")] + FileType::Go(file) => file.get_functions(), } } @@ -57,6 +66,11 @@ impl FileTrait for FileType { let filtered = file.filter_by(filter)?; Ok(FileType::C(filtered)) } + #[cfg(feature = "unstable")] + FileType::Go(file) => { + let filtered = file.filter_by(filter)?; + Ok(FileType::Go(filtered)) + } } } @@ -66,6 +80,8 @@ impl FileTrait for FileType { Self::Python(file) => file.get_current(), #[cfg(feature = "c_lang")] FileType::C(file) => file.get_current(), + #[cfg(feature = "unstable")] + FileType::Go(file) => file.get_current(), } } } @@ -77,6 +93,8 @@ impl fmt::Display for FileType { Self::Python(file) => write!(f, "{}", file), #[cfg(feature = "c_lang")] FileType::C(file) => write!(f, "{}", file), + #[cfg(feature = "unstable")] + FileType::Go(file) => write!(f, "{}", file), } } } From b1800d0121ee7c31ce4960b90fa87462982be4af Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Wed, 19 Oct 2022 14:28:01 -0400 Subject: [PATCH 056/172] cargo fmted --- git-function-history-lib/src/languages/go.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index b276f58b..c1e2252d 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -168,7 +168,6 @@ pub(crate) fn find_function_in_file( .collect::>()) } - #[derive(Debug, Clone, PartialEq, Eq)] pub enum Filter { FunctionWithParameter(String), @@ -182,11 +181,15 @@ impl Filter { Filter::FunctionWithParameter(param) => { func.parameters.iter().any(|x| x.contains(param)) } - Filter::FunctionWithReturnType(ret) => func.returns.as_ref().map(|x| x.contains(ret)).unwrap_or(false), + Filter::FunctionWithReturnType(ret) => func + .returns + .as_ref() + .map(|x| x.contains(ret)) + .unwrap_or(false), Filter::FunctionInLines(start, end) => { let (s, e) = func.get_total_lines(); s >= *start && e <= *end } } } -} \ No newline at end of file +} From 446e7fffda24dfd6f2efa4450a122d22d047df4c Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Wed, 19 Oct 2022 14:47:55 -0400 Subject: [PATCH 057/172] added go test fixed go formating --- git-function-history-lib/src/languages/go.rs | 16 +------------- git-function-history-lib/src/lib.rs | 21 +++++++++++++++++++ .../src/test_functions.go | 1 + 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index c1e2252d..36a940a1 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -33,20 +33,7 @@ impl GoFunction { impl fmt::Display for GoFunction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.name)?; - if !self.parameters.is_empty() { - write!(f, "(")?; - for (i, param) in self.parameters.iter().enumerate() { - if i != 0 { - write!(f, ", ")?; - } - write!(f, "{}", param)?; - } - write!(f, ")")?; - } - if let Some(ret) = &self.returns { - write!(f, " -> {}", ret)?; - } + write!(f, "{}", self.body)?; Ok(()) } } @@ -151,7 +138,6 @@ pub(crate) fn find_function_in_file( .collect(), ) .filter(|x: &String| !x.is_empty()); - // TODO: get parent functions Some(GoFunction::new( func.name.name, body, diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 252bfd4f..fe8b63e2 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -688,4 +688,25 @@ mod tests { println!("time taken: {}", after.num_seconds()); assert!(t.is_ok()); } + + #[test] + #[cfg(feature = "unstable")] + fn go() { + let now = Utc::now(); + let output = get_function_history( + "empty_test", + &FileFilterType::Relative("src/test_functions.go".to_string()), + &Filter::None, + &languages::Language::Go, + ); + let after = Utc::now() - now; + println!("time taken: {}", after.num_seconds()); + match &output { + Ok(functions) => { + println!("{}", functions); + } + Err(e) => println!("{}", e), + } + assert!(output.is_ok()); + } } diff --git a/git-function-history-lib/src/test_functions.go b/git-function-history-lib/src/test_functions.go index 84000d2a..b4bc784a 100644 --- a/git-function-history-lib/src/test_functions.go +++ b/git-function-history-lib/src/test_functions.go @@ -8,6 +8,7 @@ import ( func main() { fmt.Println("Hello World!") } +// doc comment func empty_test() { fmt.Println("Hello World!") From 17299d8a23be9c7c9d89e2d7e2023c40e4c8cf03 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 19 Oct 2022 21:46:45 -0400 Subject: [PATCH 058/172] intial ruby support still a lot of todos clippied & fmted too --- cargo-function-history/src/app/mod.rs | 1 + git-function-history-gui/src/lib.rs | 1 + git-function-history-lib/src/languages/mod.rs | 10 +- .../src/languages/python.rs | 39 ++-- .../src/languages/ruby.rs | 174 ++++++++++++++++++ .../src/languages/rust.rs | 105 +++++------ git-function-history-lib/src/lib.rs | 75 +++++--- .../src/test_functions.rb | 11 ++ git-function-history-lib/src/types.rs | 16 +- 9 files changed, 316 insertions(+), 116 deletions(-) create mode 100644 git-function-history-lib/src/test_functions.rb diff --git a/cargo-function-history/src/app/mod.rs b/cargo-function-history/src/app/mod.rs index b60ecae1..0b509155 100644 --- a/cargo-function-history/src/app/mod.rs +++ b/cargo-function-history/src/app/mod.rs @@ -341,6 +341,7 @@ impl App { &"c" => Language::C, #[cfg(feature = "unstable")] &"go" => Language::Go, + &"ruby" => Language::Ruby, _ => { self.status = Status::Error("Invalid language".to_string()); diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index b387fcd2..f11836b4 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -602,6 +602,7 @@ impl eframe::App for MyEguiApp { Language::All => "Language", #[cfg(feature = "unstable")] Language::Go => "Go", + Language::Ruby => "Ruby", }; egui::ComboBox::from_id_source("search_language_combo_box") .selected_text(text) diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index cd04a6fe..8ec47ea6 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -4,7 +4,7 @@ use std::{ fmt::{self, Display}, }; // TODO: lisp/scheme js go(https://docs.rs/gosyn/latest/gosyn/) ruby(https://docs.rs/lib-ruby-parser/latest/lib_ruby_parser/) java?(https://github.com/tanin47/javaparser.rs) php?(https://docs.rs/tagua-parser/0.1.0/tagua_parser/) -use self::{python::PythonFunction, rust::RustFunction}; +use self::{python::PythonFunction, ruby::RubyFunction, rust::RustFunction}; #[cfg(feature = "c_lang")] use self::c::CFunction; @@ -23,6 +23,8 @@ pub enum Language { #[cfg(feature = "unstable")] /// The go language Go, + /// the Ruby language + Ruby, /// all available languages All, } @@ -38,6 +40,8 @@ pub enum LanguageFilter { #[cfg(feature = "unstable")] /// go filter Go(go::Filter), + /// ruby filter + Ruby(ruby::Filter), } impl Language { @@ -50,6 +54,7 @@ impl Language { #[cfg(feature = "unstable")] "go" => Ok(Self::Go), "all" => Ok(Self::All), + "ruby" => Ok(Self::Ruby), _ => Err(format!("Unknown language: {}", s))?, } } @@ -64,6 +69,7 @@ impl fmt::Display for Language { Self::C => write!(f, "c"), #[cfg(feature = "unstable")] Self::Go => write!(f, "go"), + Self::Ruby => write!(f, "ruby"), Self::All => write!(f, "all"), } } @@ -254,6 +260,7 @@ make_file!(RustFile, RustFunction, Rust); make_file!(CFile, CFunction, C); #[cfg(feature = "unstable")] make_file!(GoFile, GoFunction, Go); +make_file!(RubyFile, RubyFunction, Ruby); use std::path::MAIN_SEPARATOR; // make macro that auto genertes the test parse__file_time macro_rules! make_file_time_test { @@ -283,4 +290,5 @@ mod lang_tests { make_file_time_test!(c_parses, c, c); #[cfg(feature = "unstable")] make_file_time_test!(go_parses, go, go); + make_file_time_test!(ruby_parses, rb, ruby); } diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 4e864d56..0ae9c2d5 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -308,12 +308,9 @@ impl Filter { impl FunctionTrait for PythonFunction { fn get_tops(&self) -> Vec { let mut tops = Vec::new(); - match &self.class { - Some(block) => { - tops.push(block.top.clone()); - } - None => {} - } + self.class.as_ref().map_or((), |block| { + tops.push(block.top.clone()); + }); for parent in &self.parent { tops.push(parent.top.clone()); } @@ -321,30 +318,24 @@ impl FunctionTrait for PythonFunction { } fn get_total_lines(&self) -> (usize, usize) { - match &self.class { - Some(block) => block.lines, - None => { - let mut start = self.lines.0; - let mut end = self.lines.1; - for parent in &self.parent { - if parent.lines.0 < start { - start = parent.lines.0; - end = parent.lines.1; - } + self.class.as_ref().map_or_else(|| { + let mut start = self.lines.0; + let mut end = self.lines.1; + for parent in &self.parent { + if parent.lines.0 < start { + start = parent.lines.0; + end = parent.lines.1; } - (start, end) } - } + (start, end) + }, |block| block.lines) } fn get_bottoms(&self) -> Vec { let mut bottoms = Vec::new(); - match &self.class { - Some(block) => { - bottoms.push(block.bottom.clone()); - } - None => {} - } + self.class.as_ref().map_or((), |block| { + bottoms.push(block.bottom.clone()); + }); for parent in &self.parent { bottoms.push(parent.bottom.clone()); } diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 8b137891..c5d0a4e1 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -1 +1,175 @@ +use std::{error::Error, fmt}; +use lib_ruby_parser::{ + nodes::{Class, Def}, + Parser, ParserOptions, +}; + +use crate::UnwrapToError; + +use super::FunctionTrait; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct RubyFunction { + pub name: String, + pub lines: (usize, usize), + pub class: Option, + pub args: Vec, + pub body: String, +} + +impl RubyFunction { + pub fn new( + name: String, + lines: (usize, usize), + class: Option, + args: Vec, + body: String, + ) -> Self { + Self { + name, + lines, + class, + args, + body, + } + } +} + +impl fmt::Display for RubyFunction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.class { + Some(class) => write!(f, "{}", class.top)?, + None => {} + } + write!(f, "{}", self.body)?; + match &self.class { + Some(class) => write!(f, "{}", class.bottom)?, + None => {} + } + Ok(()) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct RubyClass { + pub name: String, + pub line: (usize, usize), + pub superclass: Option, + pub top: String, + pub bottom: String, +} + +pub(crate) fn find_function_in_file( + file_contents: &str, + name: &str, +) -> Result, Box> { + let parser = Parser::new(file_contents, ParserOptions::default()); + let parsed = parser.do_parse(); + let ast = parsed.ast.unwrap_to_error("Failed to parse file")?; + let fns = get_functions_from_node(&ast, &None, name); + fns.iter() + .map(|(f, c)| { + let class = c.as_ref().map(|c| RubyClass { + name: parser_class_name(c), + line: (f.expression_l.begin, f.expression_l.end), + superclass: None, + // TODO: get top and bottom + top: String::new(), + bottom: String::new(), + }); + Ok(RubyFunction { + name: f.name.clone(), + // TODO: turn the positions into lines + lines: (f.expression_l.begin, f.expression_l.end), + class, + // TODO: put line numbers in here + body: f + .expression_l + .source(&parsed.input) + .expect("Failed to get function body"), + args: f + .args + .clone() + .map_or_else(Vec::new, |a| parse_args_from_node(&a)), + }) + }) + .collect() +} + +pub fn get_functions_from_node( + node: &lib_ruby_parser::Node, + class: &Option, + name: &str, +) -> Vec<(Def, Option)> { + match node { + lib_ruby_parser::Node::Def(def) => { + if def.name == name { + vec![(def.clone(), class.clone())] + } else { + vec![] + } + } + lib_ruby_parser::Node::Class(class) => { + let mut functions = vec![]; + for child in &class.body { + functions.extend(get_functions_from_node(child, &Some(class.clone()), name)); + } + functions + } + lib_ruby_parser::Node::Begin(stat) => { + let mut functions = vec![]; + for child in &stat.statements { + functions.extend(get_functions_from_node(child, class, name)); + } + functions + } + _ => vec![], + } +} + +fn parse_args_from_node(node: &lib_ruby_parser::Node) -> Vec { + // match node { + // lib_ruby_parser::Node::Args(args) => args + // .args + // .iter() + // .map(|arg| arg.name.str_type().to_string()) + // .collect(), + // _ => vec![], + // } + vec![] +} + +fn parser_class_name(class: &Class) -> String { + String::new() +} + +impl FunctionTrait for RubyFunction { + crate::impl_function_trait!(RubyFunction); + + fn get_tops(&self) -> Vec { + self.class.as_ref().map_or_else(Vec::new, |c| vec![c.top.clone()]) + } + + fn get_bottoms(&self) -> Vec { + self.class.as_ref().map_or_else(Vec::new, |c| vec![c.bottom.clone()]) + } + + fn get_total_lines(&self) -> (usize, usize) { + self.class.as_ref().map_or(self.lines, |c| c.line) + } +} +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Filter { + FunctionInLines((usize, usize)), +} + +impl Filter { + pub const fn matches(&self, function: &RubyFunction) -> bool { + match self { + Self::FunctionInLines((start, end)) => { + function.lines.0 >= *start && function.lines.1 <= *end + } + } + } +} diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 998ca0c8..026dcf80 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -113,12 +113,9 @@ impl FunctionBlock { map.insert("lifetime generics".to_string(), self.lifetime.join(",")); map.insert("attributes".to_string(), self.attributes.join(",")); map.insert("doc comments".to_string(), self.doc_comments.join(",")); - match &self.return_type { - None => {} - Some(return_type) => { - map.insert("return type".to_string(), return_type.clone()); - } - }; + self.return_type.as_ref().map_or((), |return_type| { + map.insert("return type".to_string(), return_type.clone()); + }); map } } @@ -290,17 +287,14 @@ pub(crate) fn find_function_in_file( bottom: stuff.1 .1, lines: (stuff.0 .0, stuff.0 .1), return_type: function.ret_type().map(|ty| ty.to_string()), - arguments: match f.param_list() { - Some(args) => args - .params() - .filter_map(|arg| { - arg.to_string() - .rsplit_once(": ") - .map(|x| (x.0.to_string(), x.1.to_string())) - }) - .collect::>(), - None => HashMap::new(), - }, + arguments: f.param_list().map_or_else( HashMap::new, |args| args + .params() + .filter_map(|arg| { + arg.to_string() + .rsplit_once(": ") + .map(|x| (x.0.to_string(), x.1.to_string())) + }) + .collect::>()), attributes: attr.1, doc_comments: attr.0, }); @@ -329,17 +323,14 @@ pub(crate) fn find_function_in_file( block: parent_block, function: parent_fn, return_type: f.ret_type().map(|ty| ty.to_string()), - arguments: match f.param_list() { - Some(args) => args - .params() - .filter_map(|arg| { - arg.to_string() - .rsplit_once(": ") - .map(|x| (x.0.to_string(), x.1.to_string())) - }) - .collect::>(), - None => HashMap::new(), - }, + arguments: f.param_list().map_or_else(HashMap::new, |args| args + .params() + .filter_map(|arg| { + arg.to_string() + .rsplit_once(": ") + .map(|x| (x.0.to_string(), x.1.to_string())) + }) + .collect::>()), lifetime: generics.1, generics: generics.0, lines: (stuff.0 .0, stuff.0 .1), @@ -436,17 +427,14 @@ fn get_stuff( #[inline] fn get_genrerics_and_lifetime(block: &T) -> (Vec, Vec) { // TODO: map trait bounds from where clauses to the generics and also use type_or_const_params - match block.generic_param_list() { - None => (vec![], vec![]), - Some(gt) => ( - gt.generic_params() - .map(|gt| gt.to_string()) - .collect::>(), - gt.lifetime_params() - .map(|lt| lt.to_string()) - .collect::>(), - ), - } + block.generic_param_list().map_or_else(|| (vec![], vec![]), |gt| ( + gt.generic_params() + .map(|gt| gt.to_string()) + .collect::>(), + gt.lifetime_params() + .map(|lt| lt.to_string()) + .collect::>(), + )) } #[inline] fn get_doc_comments_and_attrs(block: &T) -> (Vec, Vec) { @@ -508,12 +496,9 @@ impl Filter { impl FunctionTrait for RustFunction { fn get_tops(&self) -> Vec { let mut tops = Vec::new(); - match &self.block { - Some(block) => { - tops.push(block.top.clone()); - } - None => {} - } + self.block.as_ref().map_or((), |block| { + tops.push(block.top.clone()); + }); for parent in &self.function { tops.push(parent.top.clone()); } @@ -521,30 +506,24 @@ impl FunctionTrait for RustFunction { } fn get_total_lines(&self) -> (usize, usize) { - match &self.block { - Some(block) => (block.lines.0, block.lines.1), - None => { - let mut start = self.lines.0; - let mut end = self.lines.1; - for parent in &self.function { - if parent.lines.0 < start { - start = parent.lines.0; - end = parent.lines.1; - } + self.block.as_ref().map_or_else(|| { + let mut start = self.lines.0; + let mut end = self.lines.1; + for parent in &self.function { + if parent.lines.0 < start { + start = parent.lines.0; + end = parent.lines.1; } - (start, end) } - } + (start, end) + }, |block| (block.lines.0, block.lines.1)) } fn get_bottoms(&self) -> Vec { let mut bottoms = Vec::new(); - match &self.block { - Some(block) => { - bottoms.push(block.bottom.clone()); - } - None => {} - } + self.block.as_ref().map_or((), |block| { + bottoms.push(block.bottom.clone()); + }); for parent in &self.function { bottoms.push(parent.bottom.clone()); } diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index fe8b63e2..11a25673 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -18,7 +18,7 @@ pub mod languages; /// Different types that can extracted from the result of `get_function_history`. pub mod types; -use languages::{rust, LanguageFilter}; +use languages::{rust, LanguageFilter, RubyFile}; use languages::{PythonFile, RustFile}; #[cfg(feature = "parallel")] @@ -171,19 +171,19 @@ pub fn get_function_history( let mut parts = line.split(';'); let id = parts .next() - .unwrap_to_error("no id found in git command output"); + .unwrap_to_error_sync("no id found in git command output"); let date = parts .next() - .unwrap_to_error("date is missing from git command output"); + .unwrap_to_error_sync("date is missing from git command output"); let author = parts .next() - .unwrap_to_error("author is missing from git command output"); + .unwrap_to_error_sync("author is missing from git command output"); let email = parts .next() - .unwrap_to_error("email is missing from git command output"); + .unwrap_to_error_sync("email is missing from git command output"); let message = parts .next() - .unwrap_to_error("message is missing from git command output"); + .unwrap_to_error_sync("message is missing from git command output"); Ok((id?, date?, author?, email?, message?)) }) .collect::, Box>>()?; @@ -215,11 +215,17 @@ pub fn get_function_history( Err(format!("file is not a rust file: {}", path))?; } } + Language::Ruby => { + if !path.ends_with(".rb") { + Err(format!("file is not a ruby file: {}", path))?; + } + } Language::All => { if !path.ends_with(".rs") || !path.ends_with(".py") || !path.ends_with(".c") || !path.ends_with(".h") + || !path.ends_with(".rb") { Err(format!("file is not supported: {}", path))?; } @@ -236,17 +242,14 @@ pub fn get_function_history( | FileFilterType::Relative(_) | FileFilterType::None | FileFilterType::Directory(_) => { - match find_function_in_commit_with_filetype(commit.0, name, file, *langs) { - Ok(contents) => Some(Commit::new( - commit.0.to_string(), - contents, - commit.1, - commit.2.to_string(), - commit.3.to_string(), - commit.4.to_string(), - )), - Err(_) => None, - } + find_function_in_commit_with_filetype(commit.0, name, file, *langs).map_or(None, |contents| Some(Commit::new( + commit.0.to_string(), + contents, + commit.1, + commit.2.to_string(), + commit.3.to_string(), + commit.4.to_string(), + ))) } }) .collect(); @@ -408,6 +411,11 @@ fn find_function_in_commit_with_filetype( files.push(file); } } + Language::Ruby => { + if file.ends_with(".rb") { + files.push(file); + } + } Language::All => { if file.ends_with(".rs") || file.ends_with(".py") @@ -416,6 +424,7 @@ fn find_function_in_commit_with_filetype( || file.ends_with(".h") // TODO: use cfg!() macro to check if unstable is enabled || file.ends_with(".go") + || file.ends_with(".rb") { files.push(file); } @@ -470,6 +479,13 @@ fn find_function_in_file_with_commit( functions, ))) } + Language::Ruby => { + let functions = languages::ruby::find_function_in_file(&fc, name)?; + Ok(FileType::Ruby(RubyFile::new( + file_path.to_string(), + functions, + ))) + } Language::All => match file_path.split('.').last() { Some("rs") => { let functions = rust::find_function_in_file(&fc, name)?; @@ -490,21 +506,34 @@ fn find_function_in_file_with_commit( functions, ))) } + #[cfg(feature = "unstable")] + Some("go") => { + let functions = languages::go::find_function_in_file(&fc, name)?; + Ok(FileType::Go(GoFile::new(file_path.to_string(), functions))) + } + Some("rb") => { + let functions = languages::ruby::find_function_in_file(&fc, name)?; + Ok(FileType::Ruby(RubyFile::new( + file_path.to_string(), + functions, + ))) + } _ => Err("unknown file type")?, }, } } trait UnwrapToError { - fn unwrap_to_error(self, message: &str) -> Result>; + fn unwrap_to_error_sync(self, message: &str) -> Result>; + fn unwrap_to_error(self, message: &str) -> Result>; } impl UnwrapToError for Option { - fn unwrap_to_error(self, message: &str) -> Result> { - match self { - Some(val) => Ok(val), - None => Err(message.to_string().into()), - } + fn unwrap_to_error_sync(self, message: &str) -> Result> { + self.map_or_else(|| Err(message.to_string().into()), |val| Ok(val)) + } + fn unwrap_to_error(self, message: &str) -> Result> { + self.map_or_else(|| Err(message.to_string().into()), |val| Ok(val)) } } diff --git a/git-function-history-lib/src/test_functions.rb b/git-function-history-lib/src/test_functions.rb new file mode 100644 index 00000000..1f2f73bd --- /dev/null +++ b/git-function-history-lib/src/test_functions.rb @@ -0,0 +1,11 @@ +def main() + puts "Hello World" +end + +def empty_test() +end + +class Test + def empty_test() + end +end \ No newline at end of file diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 06070b12..2e1641c0 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -9,7 +9,7 @@ use std::{ }; use crate::{ - languages::{FileTrait, FunctionTrait, PythonFile, RustFile}, + languages::{FileTrait, FunctionTrait, PythonFile, RubyFile, RustFile}, Filter, }; @@ -27,6 +27,7 @@ pub enum FileType { C(CFile), #[cfg(feature = "unstable")] Go(GoFile), + Ruby(RubyFile), } impl FileTrait for FileType { @@ -38,6 +39,7 @@ impl FileTrait for FileType { FileType::C(file) => file.get_file_name(), #[cfg(feature = "unstable")] FileType::Go(file) => file.get_file_name(), + Self::Ruby(file) => file.get_file_name(), } } fn get_functions(&self) -> Vec> { @@ -48,6 +50,7 @@ impl FileTrait for FileType { FileType::C(file) => file.get_functions(), #[cfg(feature = "unstable")] FileType::Go(file) => file.get_functions(), + Self::Ruby(file) => file.get_functions(), } } @@ -71,6 +74,10 @@ impl FileTrait for FileType { let filtered = file.filter_by(filter)?; Ok(FileType::Go(filtered)) } + Self::Ruby(file) => { + let filtered = file.filter_by(filter)?; + Ok(Self::Ruby(filtered)) + } } } @@ -82,6 +89,7 @@ impl FileTrait for FileType { FileType::C(file) => file.get_current(), #[cfg(feature = "unstable")] FileType::Go(file) => file.get_current(), + Self::Ruby(file) => file.get_current(), } } } @@ -95,6 +103,7 @@ impl fmt::Display for FileType { FileType::C(file) => write!(f, "{}", file), #[cfg(feature = "unstable")] FileType::Go(file) => write!(f, "{}", file), + Self::Ruby(file) => write!(f, "{}", file), } } } @@ -431,9 +440,6 @@ trait ErrorToOption { impl ErrorToOption for Result> { fn to_option(self) -> Option { - match self { - Ok(t) => Some(t), - Err(_) => None, - } + self.map_or(None, |t| Some(t)) } } From 24d21352eddb48bf5bd23b1293c7a1261a799d9f Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 20 Oct 2022 09:29:53 -0400 Subject: [PATCH 059/172] ruby function can now get function arguments, and ruby classes can get their name --- git-function-history-lib/src/languages/mod.rs | 10 ++++++ .../src/languages/ruby.rs | 31 +++++++++++++------ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 8ec47ea6..57e1d46e 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -275,6 +275,16 @@ macro_rules! make_file_time_test { let start = std::time::Instant::now(); let ok = $function::find_function_in_file(&file, "empty_test"); let end = std::time::Instant::now(); + match &ok { + Ok(hist) => { + for i in hist { + println!("{}", i); + } + } + Err(_) => { + + } + } println!("{} took {:?}", stringify!($name), end - start); assert!(ok.is_ok()); } diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index c5d0a4e1..0cb60404 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -72,6 +72,7 @@ pub(crate) fn find_function_in_file( .map(|(f, c)| { let class = c.as_ref().map(|c| RubyClass { name: parser_class_name(c), + // TODO: turn the positions into lines line: (f.expression_l.begin, f.expression_l.end), superclass: None, // TODO: get top and bottom @@ -129,19 +130,31 @@ pub fn get_functions_from_node( } fn parse_args_from_node(node: &lib_ruby_parser::Node) -> Vec { - // match node { - // lib_ruby_parser::Node::Args(args) => args - // .args - // .iter() - // .map(|arg| arg.name.str_type().to_string()) - // .collect(), - // _ => vec![], - // } + match node { + lib_ruby_parser::Node::Args(args) => args + .args + .iter() + .map(|arg| match arg { + lib_ruby_parser::Node::Arg(arg) => arg.name.clone(), + lib_ruby_parser::Node::Kwarg(arg) => arg.name.clone(), + lib_ruby_parser::Node::Kwoptarg(arg) => arg.name.clone(), + lib_ruby_parser::Node::Optarg(arg) => arg.name.clone(), + lib_ruby_parser::Node::Restarg(arg) => arg.name.as_ref().map_or_else(String::new, |f| f.to_string()).clone(), + lib_ruby_parser::Node::Kwrestarg(arg) => arg.name.as_ref().map_or_else(String::new, |f| f.to_string()).clone(), + _ => String::new(), + }) + + .filter(|f| !f.is_empty()).collect(), + _ => vec![], + }; vec![] } fn parser_class_name(class: &Class) -> String { - String::new() + match class.name.as_ref() { + lib_ruby_parser::Node::Const(constant) => constant.name.clone(), + _ => String::new(), + } } impl FunctionTrait for RubyFunction { From d1b4b7418b83232f291981994039fdc356ffcb09 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 20 Oct 2022 09:52:38 -0400 Subject: [PATCH 060/172] added line numbers to ruby functions --- git-function-history-lib/src/languages/mod.rs | 2 +- .../src/languages/ruby.rs | 54 ++++++++++++++++--- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 57e1d46e..7818e919 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -261,7 +261,7 @@ make_file!(CFile, CFunction, C); #[cfg(feature = "unstable")] make_file!(GoFile, GoFunction, Go); make_file!(RubyFile, RubyFunction, Ruby); -use std::path::MAIN_SEPARATOR; + // make macro that auto genertes the test parse__file_time macro_rules! make_file_time_test { ($name:ident, $extname:ident, $function:ident) => { diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 0cb60404..9facab85 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -38,6 +38,7 @@ impl RubyFunction { impl fmt::Display for RubyFunction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + println!("{:?}", self.class); match &self.class { Some(class) => write!(f, "{}", class.top)?, None => {} @@ -70,25 +71,66 @@ pub(crate) fn find_function_in_file( let fns = get_functions_from_node(&ast, &None, name); fns.iter() .map(|(f, c)| { + let mut start_line = 0; + for i in file_contents.chars().enumerate() { + if i.1 == '\n' { + if i.0 > f.expression_l.begin { + break; + } + start_line += 1; + } + } + let mut end_line = 0; + for i in file_contents.chars().enumerate() { + if i.1 == '\n' { + if i.0 > f.expression_l.end { + break; + } + end_line += 1; + } + } let class = c.as_ref().map(|c| RubyClass { name: parser_class_name(c), - // TODO: turn the positions into lines - line: (f.expression_l.begin, f.expression_l.end), + line: (start_line, end_line), superclass: None, // TODO: get top and bottom top: String::new(), bottom: String::new(), }); + // get the lines from map using f.expression_l.begin and f.expression_l.end + let mut start_line = 0; + for i in file_contents.chars().enumerate() { + if i.1 == '\n' { + if i.0 > f.expression_l.begin { + break; + } + start_line += 1; + } + } + let mut end_line = 0; + for i in file_contents.chars().enumerate() { + if i.1 == '\n' { + if i.0 > f.expression_l.end { + break; + } + end_line += 1; + } + } + let mut starts = start_line; Ok(RubyFunction { name: f.name.clone(), - // TODO: turn the positions into lines - lines: (f.expression_l.begin, f.expression_l.end), + lines: (start_line, end_line), class, - // TODO: put line numbers in here + // TODO: start at the beginning of the line of the func keyword body: f .expression_l .source(&parsed.input) - .expect("Failed to get function body"), + .expect("Failed to get function body").lines() + .map(|l| { + starts += 1; + format!("{}: {}\n", starts, l,) + }) + .collect(), args: f .args .clone() From 7b049dcdb3ad825f5e5bee0f3c8e58281ac68916 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 20 Oct 2022 10:47:16 -0400 Subject: [PATCH 061/172] did some more stuff fmted + clippied --- git-function-history-lib/src/languages/mod.rs | 4 +- .../src/languages/python.rs | 23 +++--- .../src/languages/ruby.rs | 32 +++++--- .../src/languages/rust.rs | 78 +++++++++++-------- git-function-history-lib/src/lib.rs | 11 ++- .../src/test_functions.rb | 4 + 6 files changed, 92 insertions(+), 60 deletions(-) diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 7818e919..29733fe7 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -281,9 +281,7 @@ macro_rules! make_file_time_test { println!("{}", i); } } - Err(_) => { - - } + Err(_) => {} } println!("{} took {:?}", stringify!($name), end - start); assert!(ok.is_ok()); diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 0ae9c2d5..d150896e 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -318,17 +318,20 @@ impl FunctionTrait for PythonFunction { } fn get_total_lines(&self) -> (usize, usize) { - self.class.as_ref().map_or_else(|| { - let mut start = self.lines.0; - let mut end = self.lines.1; - for parent in &self.parent { - if parent.lines.0 < start { - start = parent.lines.0; - end = parent.lines.1; + self.class.as_ref().map_or_else( + || { + let mut start = self.lines.0; + let mut end = self.lines.1; + for parent in &self.parent { + if parent.lines.0 < start { + start = parent.lines.0; + end = parent.lines.1; + } } - } - (start, end) - }, |block| block.lines) + (start, end) + }, + |block| block.lines, + ) } fn get_bottoms(&self) -> Vec { diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 9facab85..43fa182d 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -38,7 +38,6 @@ impl RubyFunction { impl fmt::Display for RubyFunction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - println!("{:?}", self.class); match &self.class { Some(class) => write!(f, "{}", class.top)?, None => {} @@ -72,6 +71,7 @@ pub(crate) fn find_function_in_file( fns.iter() .map(|(f, c)| { let mut start_line = 0; + // TODO: get signature and bottom of class for i in file_contents.chars().enumerate() { if i.1 == '\n' { if i.0 > f.expression_l.begin { @@ -97,6 +97,7 @@ pub(crate) fn find_function_in_file( top: String::new(), bottom: String::new(), }); + let mut start = f.expression_l.begin; // get the lines from map using f.expression_l.begin and f.expression_l.end let mut start_line = 0; for i in file_contents.chars().enumerate() { @@ -104,6 +105,7 @@ pub(crate) fn find_function_in_file( if i.0 > f.expression_l.begin { break; } + start = i.0; start_line += 1; } } @@ -121,11 +123,13 @@ pub(crate) fn find_function_in_file( name: f.name.clone(), lines: (start_line, end_line), class, - // TODO: start at the beginning of the line of the func keyword body: f .expression_l + .with_begin(start) .source(&parsed.input) - .expect("Failed to get function body").lines() + .expect("Failed to get function body") + .trim_matches('\n') + .lines() .map(|l| { starts += 1; format!("{}: {}\n", starts, l,) @@ -181,12 +185,18 @@ fn parse_args_from_node(node: &lib_ruby_parser::Node) -> Vec { lib_ruby_parser::Node::Kwarg(arg) => arg.name.clone(), lib_ruby_parser::Node::Kwoptarg(arg) => arg.name.clone(), lib_ruby_parser::Node::Optarg(arg) => arg.name.clone(), - lib_ruby_parser::Node::Restarg(arg) => arg.name.as_ref().map_or_else(String::new, |f| f.to_string()).clone(), - lib_ruby_parser::Node::Kwrestarg(arg) => arg.name.as_ref().map_or_else(String::new, |f| f.to_string()).clone(), + lib_ruby_parser::Node::Restarg(arg) => arg + .name + .as_ref() + .map_or_else(String::new, ToString::to_string), + lib_ruby_parser::Node::Kwrestarg(arg) => arg + .name + .as_ref() + .map_or_else(String::new, ToString::to_string), _ => String::new(), }) - - .filter(|f| !f.is_empty()).collect(), + .filter(|f| !f.is_empty()) + .collect(), _ => vec![], }; vec![] @@ -203,11 +213,15 @@ impl FunctionTrait for RubyFunction { crate::impl_function_trait!(RubyFunction); fn get_tops(&self) -> Vec { - self.class.as_ref().map_or_else(Vec::new, |c| vec![c.top.clone()]) + self.class + .as_ref() + .map_or_else(Vec::new, |c| vec![c.top.clone()]) } fn get_bottoms(&self) -> Vec { - self.class.as_ref().map_or_else(Vec::new, |c| vec![c.bottom.clone()]) + self.class + .as_ref() + .map_or_else(Vec::new, |c| vec![c.bottom.clone()]) } fn get_total_lines(&self) -> (usize, usize) { diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 026dcf80..098df04b 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -287,14 +287,15 @@ pub(crate) fn find_function_in_file( bottom: stuff.1 .1, lines: (stuff.0 .0, stuff.0 .1), return_type: function.ret_type().map(|ty| ty.to_string()), - arguments: f.param_list().map_or_else( HashMap::new, |args| args - .params() - .filter_map(|arg| { - arg.to_string() - .rsplit_once(": ") - .map(|x| (x.0.to_string(), x.1.to_string())) - }) - .collect::>()), + arguments: f.param_list().map_or_else(HashMap::new, |args| { + args.params() + .filter_map(|arg| { + arg.to_string() + .rsplit_once(": ") + .map(|x| (x.0.to_string(), x.1.to_string())) + }) + .collect::>() + }), attributes: attr.1, doc_comments: attr.0, }); @@ -323,14 +324,15 @@ pub(crate) fn find_function_in_file( block: parent_block, function: parent_fn, return_type: f.ret_type().map(|ty| ty.to_string()), - arguments: f.param_list().map_or_else(HashMap::new, |args| args - .params() - .filter_map(|arg| { - arg.to_string() - .rsplit_once(": ") - .map(|x| (x.0.to_string(), x.1.to_string())) - }) - .collect::>()), + arguments: f.param_list().map_or_else(HashMap::new, |args| { + args.params() + .filter_map(|arg| { + arg.to_string() + .rsplit_once(": ") + .map(|x| (x.0.to_string(), x.1.to_string())) + }) + .collect::>() + }), lifetime: generics.1, generics: generics.0, lines: (stuff.0 .0, stuff.0 .1), @@ -427,14 +429,19 @@ fn get_stuff( #[inline] fn get_genrerics_and_lifetime(block: &T) -> (Vec, Vec) { // TODO: map trait bounds from where clauses to the generics and also use type_or_const_params - block.generic_param_list().map_or_else(|| (vec![], vec![]), |gt| ( - gt.generic_params() - .map(|gt| gt.to_string()) - .collect::>(), - gt.lifetime_params() - .map(|lt| lt.to_string()) - .collect::>(), - )) + block.generic_param_list().map_or_else( + || (vec![], vec![]), + |gt| { + ( + gt.generic_params() + .map(|gt| gt.to_string()) + .collect::>(), + gt.lifetime_params() + .map(|lt| lt.to_string()) + .collect::>(), + ) + }, + ) } #[inline] fn get_doc_comments_and_attrs(block: &T) -> (Vec, Vec) { @@ -506,17 +513,20 @@ impl FunctionTrait for RustFunction { } fn get_total_lines(&self) -> (usize, usize) { - self.block.as_ref().map_or_else(|| { - let mut start = self.lines.0; - let mut end = self.lines.1; - for parent in &self.function { - if parent.lines.0 < start { - start = parent.lines.0; - end = parent.lines.1; + self.block.as_ref().map_or_else( + || { + let mut start = self.lines.0; + let mut end = self.lines.1; + for parent in &self.function { + if parent.lines.0 < start { + start = parent.lines.0; + end = parent.lines.1; + } } - } - (start, end) - }, |block| (block.lines.0, block.lines.1)) + (start, end) + }, + |block| (block.lines.0, block.lines.1), + ) } fn get_bottoms(&self) -> Vec { diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 11a25673..a4d2117e 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -241,16 +241,19 @@ pub fn get_function_history( FileFilterType::Absolute(_) | FileFilterType::Relative(_) | FileFilterType::None - | FileFilterType::Directory(_) => { - find_function_in_commit_with_filetype(commit.0, name, file, *langs).map_or(None, |contents| Some(Commit::new( + | FileFilterType::Directory(_) => find_function_in_commit_with_filetype( + commit.0, name, file, *langs, + ) + .map_or(None, |contents| { + Some(Commit::new( commit.0.to_string(), contents, commit.1, commit.2.to_string(), commit.3.to_string(), commit.4.to_string(), - ))) - } + )) + }), }) .collect(); if file_history.commit_history.is_empty() { diff --git a/git-function-history-lib/src/test_functions.rb b/git-function-history-lib/src/test_functions.rb index 1f2f73bd..a0ef67b4 100644 --- a/git-function-history-lib/src/test_functions.rb +++ b/git-function-history-lib/src/test_functions.rb @@ -8,4 +8,8 @@ def empty_test() class Test def empty_test() end + + def test() + puts "Hello World" + end end \ No newline at end of file From 58cabc0704f3afb49309c709fe051a7ed8a8b39c Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 20 Oct 2022 11:04:26 -0400 Subject: [PATCH 062/172] rubby can now get class bottom --- .../src/languages/ruby.rs | 66 ++++++++++++------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 43fa182d..7008a825 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -2,7 +2,7 @@ use std::{error::Error, fmt}; use lib_ruby_parser::{ nodes::{Class, Def}, - Parser, ParserOptions, + Loc, Parser, ParserOptions, }; use crate::UnwrapToError; @@ -70,33 +70,49 @@ pub(crate) fn find_function_in_file( let fns = get_functions_from_node(&ast, &None, name); fns.iter() .map(|(f, c)| { - let mut start_line = 0; - // TODO: get signature and bottom of class - for i in file_contents.chars().enumerate() { - if i.1 == '\n' { - if i.0 > f.expression_l.begin { - break; + let class = match c { + Some(c) => { + let mut start_line = 0; + for i in file_contents.chars().enumerate() { + if i.1 == '\n' { + if i.0 > c.expression_l.begin { + break; + } + start_line += 1; + } } - start_line += 1; - } - } - let mut end_line = 0; - for i in file_contents.chars().enumerate() { - if i.1 == '\n' { - if i.0 > f.expression_l.end { - break; + let mut end_line = 0; + let mut end_char = 0; + for i in file_contents.chars().enumerate() { + if i.1 == '\n' { + if i.0 > c.expression_l.end { + break; + } + end_char = i.0; + end_line += 1; + } } - end_line += 1; + let loc_end = Loc { + begin: end_char, + end: c.expression_l.end, + }; + Some(RubyClass { + name: parser_class_name(c), + line: (start_line, end_line), + superclass: None, + // TODO: get top signature + top: String::new(), + bottom: format!( + "{end_line}: {}", + loc_end + .source(&parsed.input) + .expect("Failed to get source") + .trim_matches('\n') + ), + }) } - } - let class = c.as_ref().map(|c| RubyClass { - name: parser_class_name(c), - line: (start_line, end_line), - superclass: None, - // TODO: get top and bottom - top: String::new(), - bottom: String::new(), - }); + None => None, + }; let mut start = f.expression_l.begin; // get the lines from map using f.expression_l.begin and f.expression_l.end let mut start_line = 0; From 7d5ddfee31b9be9774a118ce9150f3927cffdbcc Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 20 Oct 2022 11:13:58 -0400 Subject: [PATCH 063/172] updated workflows for multi langs support --- .github/workflows/cargo_clippy_lib.yml | 28 +++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cargo_clippy_lib.yml b/.github/workflows/cargo_clippy_lib.yml index 97e21e18..52bf7841 100644 --- a/.github/workflows/cargo_clippy_lib.yml +++ b/.github/workflows/cargo_clippy_lib.yml @@ -9,10 +9,36 @@ jobs: - uses: actions/checkout@v1 - run: | rustup component add clippy + rustup toolchain install nightly + - uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} - args: --all-features -p git_function_history + toolchain: nightly + args: --features unstable, c_lang -p git_function_history + nightly-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: setup rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: nightly + override: true + - name: test + run: | + cargo +nightly test -p git_function_history --features unstable, c_lang -- --nocapture + + test_clang: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: setup rust + uses: dtolnay/rust-toolchain@stable + - name: test + run: | + cargo +nightly test -p git_function_history --features c_lang -- --nocapture + test: runs-on: ubuntu-latest steps: From c5fab023151cdf26a15b7b88a6f4979dbe3701b5 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 20 Oct 2022 11:19:38 -0400 Subject: [PATCH 064/172] updated dependcies --- cargo-function-history/Cargo.toml | 2 +- function_history_backend_thread/Cargo.toml | 2 +- git-function-history-gui/Cargo.toml | 2 +- git-function-history-lib/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cargo-function-history/Cargo.toml b/cargo-function-history/Cargo.toml index 0faa03ae..23f611e4 100644 --- a/cargo-function-history/Cargo.toml +++ b/cargo-function-history/Cargo.toml @@ -19,7 +19,7 @@ unstable = ["function_history_backend_thread/unstable", "git_function_history/un [dependencies] git_function_history = { path = "../git-function-history-lib", version = "0.6.2", default-features = false} -lazy_static = "1.3.0" +lazy_static = "1.4.0" tui = { version = "0.19", features = ["crossterm"], default-features = false } crossterm = "0.25.0" tokio = { version = "1.21.2", features = ["full"] } diff --git a/function_history_backend_thread/Cargo.toml b/function_history_backend_thread/Cargo.toml index d183d728..141024d1 100644 --- a/function_history_backend_thread/Cargo.toml +++ b/function_history_backend_thread/Cargo.toml @@ -20,4 +20,4 @@ unstable = ["git_function_history/unstable"] [dependencies] git_function_history = { path = "../git-function-history-lib", version = "0.6.2", default-features = false} -log = "0.4" +log = "0.4.17" diff --git a/git-function-history-gui/Cargo.toml b/git-function-history-gui/Cargo.toml index 0d5f1bee..926e38f2 100644 --- a/git-function-history-gui/Cargo.toml +++ b/git-function-history-gui/Cargo.toml @@ -23,4 +23,4 @@ git_function_history = { path = "../git-function-history-lib", version = "0.6.2" function_history_backend_thread = { path = "../function_history_backend_thread", version = "0.2.2", default-features = false} simple_file_logger = "0.2.0" log = "0.4.17" -image = "0.24" \ No newline at end of file +image = "0.24.4" \ No newline at end of file diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 6f73878a..39c92979 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -17,7 +17,7 @@ unstable = ["dep:gosyn", "dep:javaparser"] [dependencies] chrono = "0.4.22" ra_ap_syntax = "0.0.133" -rayon = { version = "1.5.1", optional = true } +rayon = { version = "1.5.3", optional = true } rustpython-parser = "0.1.2" lib-ruby-parser = "3.0.12" gosyn = {version = "0.1.1", optional = true} From 0896a270cc20eed3a2ed1ed131c857dbc18d2aa3 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 20 Oct 2022 11:40:03 -0400 Subject: [PATCH 065/172] attempting ot fix gh actions --- .github/workflows/cargo_clippy_lib.yml | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/.github/workflows/cargo_clippy_lib.yml b/.github/workflows/cargo_clippy_lib.yml index 52bf7841..1ed83b42 100644 --- a/.github/workflows/cargo_clippy_lib.yml +++ b/.github/workflows/cargo_clippy_lib.yml @@ -8,15 +8,15 @@ jobs: steps: - uses: actions/checkout@v1 - run: | - rustup component add clippy + rustup toolchain install nightly - + rustup +nightly component add clippy - uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} toolchain: nightly args: --features unstable, c_lang -p git_function_history - nightly-test: + nightly-clang-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -29,7 +29,7 @@ jobs: run: | cargo +nightly test -p git_function_history --features unstable, c_lang -- --nocapture - test_clang: + test-clang: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -37,7 +37,7 @@ jobs: uses: dtolnay/rust-toolchain@stable - name: test run: | - cargo +nightly test -p git_function_history --features c_lang -- --nocapture + cargo test -p git_function_history --features c_lang -- --nocapture test: runs-on: ubuntu-latest @@ -47,4 +47,17 @@ jobs: uses: dtolnay/rust-toolchain@stable - name: test run: | - cargo test -p git_function_history -- --nocapture \ No newline at end of file + cargo test -p git_function_history -- --nocapture + + test-nightly: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: setup rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: nightly + override: true + - name: test + run: | + cargo +nightly test -p git_function_history --features unstable -- --nocapture \ No newline at end of file From c13004ca0eadd525a01294e6cf0d0fea2ebcb7a4 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 20 Oct 2022 14:10:14 -0400 Subject: [PATCH 066/172] started working on ruby class signatures --- git-function-history-lib/src/languages/ruby.rs | 16 +++++++++++++--- git-function-history-lib/src/test_functions.rb | 3 ++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 7008a825..3a945531 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -96,12 +96,19 @@ pub(crate) fn find_function_in_file( begin: end_char, end: c.expression_l.end, }; + let top = Loc { + begin: c.expression_l.begin, + end: c.body.as_ref().map_or(0, |b| b.expression().begin) + }; + let mut top = top.source(&parsed.input).unwrap_to_error("Failed to get source")?; + top = top.trim_end().to_string(); + top.push_str("\n"); + // TODO: add line numbers to top amd start at new line Some(RubyClass { name: parser_class_name(c), line: (start_line, end_line), superclass: None, - // TODO: get top signature - top: String::new(), + top, bottom: format!( "{end_line}: {}", loc_end @@ -160,7 +167,9 @@ pub(crate) fn find_function_in_file( .collect() } -pub fn get_functions_from_node( + + +fn get_functions_from_node( node: &lib_ruby_parser::Node, class: &Option, name: &str, @@ -218,6 +227,7 @@ fn parse_args_from_node(node: &lib_ruby_parser::Node) -> Vec { vec![] } + fn parser_class_name(class: &Class) -> String { match class.name.as_ref() { lib_ruby_parser::Node::Const(constant) => constant.name.clone(), diff --git a/git-function-history-lib/src/test_functions.rb b/git-function-history-lib/src/test_functions.rb index a0ef67b4..41a64d1b 100644 --- a/git-function-history-lib/src/test_functions.rb +++ b/git-function-history-lib/src/test_functions.rb @@ -5,7 +5,8 @@ def main() def empty_test() end -class Test +class + Test def empty_test() end From 42d856687454d1f70003c277a694f701ff20ea55 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 20 Oct 2022 14:49:10 -0400 Subject: [PATCH 067/172] started java support --- git-function-history-lib/Cargo.toml | 2 +- .../src/languages/java.rs | 53 +++++++++++++++++++ .../src/languages/ruby.rs | 9 +++- 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 39c92979..3dde4721 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -16,7 +16,7 @@ unstable = ["dep:gosyn", "dep:javaparser"] [dependencies] chrono = "0.4.22" -ra_ap_syntax = "0.0.133" +ra_ap_syntax = "0.0.134" rayon = { version = "1.5.3", optional = true } rustpython-parser = "0.1.2" lib-ruby-parser = "3.0.12" diff --git a/git-function-history-lib/src/languages/java.rs b/git-function-history-lib/src/languages/java.rs index 8b137891..5bddeb9a 100644 --- a/git-function-history-lib/src/languages/java.rs +++ b/git-function-history-lib/src/languages/java.rs @@ -1 +1,54 @@ +use std::fmt; +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct JavaFunction { + pub name: String, + pub lines: (usize, usize), + pub args: Vec, + pub body: String, + pub class: JavaClass, +} + +impl JavaFunction { + pub fn new( + name: String, + lines: (usize, usize), + args: Vec, + body: String, + class: JavaClass, + ) -> Self { + Self { + name, + lines, + args, + body, + class, + } + } +} + +impl fmt::Display for JavaFunction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.class.top)?; + write!(f, "{}", self.body)?; + write!(f, "{}", self.class.bottom)?; + Ok(()) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct JavaClass { + pub name: String, + pub line: (usize, usize), + pub top: String, + pub bottom: String, +} + +pub(crate) fn find_function_in_file( + file_contents: &str, + name: &str, + class_name: &str, +) -> Result { + let file = javaparser::parse::apply(file_contents); + Err("Not implemented".to_string()) +} \ No newline at end of file diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 3a945531..fb6d9b52 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -103,12 +103,17 @@ pub(crate) fn find_function_in_file( let mut top = top.source(&parsed.input).unwrap_to_error("Failed to get source")?; top = top.trim_end().to_string(); top.push_str("\n"); - // TODO: add line numbers to top amd start at new line + let mut starts = start_line; Some(RubyClass { name: parser_class_name(c), line: (start_line, end_line), superclass: None, - top, + top: top.lines() + .map(|l| { + starts += 1; + format!("{}: {}\n", starts, l,) + }) + .collect(), bottom: format!( "{end_line}: {}", loc_end From 24a533928b439372b8f7e7561b38cad3f739bdc1 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Fri, 21 Oct 2022 13:01:45 -0400 Subject: [PATCH 068/172] nothing speacial --- .../src/languages/java.rs | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/git-function-history-lib/src/languages/java.rs b/git-function-history-lib/src/languages/java.rs index 5bddeb9a..0689cfa7 100644 --- a/git-function-history-lib/src/languages/java.rs +++ b/git-function-history-lib/src/languages/java.rs @@ -47,8 +47,27 @@ pub struct JavaClass { pub(crate) fn find_function_in_file( file_contents: &str, name: &str, - class_name: &str, ) -> Result { - let file = javaparser::parse::apply(file_contents); + let file = javaparser::parse::apply(file_contents, "").map_err(|_| "Parse error")?; + let parsed = file.unit.clone(); + println!("{:#?}", file); Err("Not implemented".to_string()) -} \ No newline at end of file +} + +#[cfg(test)] +mod java_test { + use super::*; + + #[test] + fn java() { + let file_contents = r#" + public class Test { + public static void main(String[] args) { + System.out.println("Hello, World"); + } + } + "#; + let function = find_function_in_file(file_contents, "main").unwrap(); + + } + } \ No newline at end of file From 32632b5520ab116733a9020d6e78fc0c854001f4 Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Sun, 23 Oct 2022 00:03:37 -0400 Subject: [PATCH 069/172] more condintional compilation --- git-function-history-lib/Cargo.toml | 3 ++- git-function-history-lib/src/lib.rs | 29 +++++++++++++++++------------ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 3dde4721..13c0cefe 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -21,4 +21,5 @@ rayon = { version = "1.5.3", optional = true } rustpython-parser = "0.1.2" lib-ruby-parser = "3.0.12" gosyn = {version = "0.1.1", optional = true} -javaparser = {git = "https://github.com/tanin47/javaparser.rs", optional = true} \ No newline at end of file +javaparser = {git = "https://github.com/tanin47/javaparser.rs", optional = true} +cfg-if = "1.0.0" \ No newline at end of file diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index a4d2117e..9793246f 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -14,7 +14,7 @@ clippy::return_self_not_must_use )] pub mod languages; - +use cfg_if::cfg_if; /// Different types that can extracted from the result of `get_function_history`. pub mod types; @@ -48,7 +48,6 @@ pub enum FileFilterType { None, } -// TODO: Add support for filtering by generic parameters, lifetimes, and return types. /// This is filter enum is used when you want to lookup a function with the filter of filter a previous lookup. #[derive(Debug, Clone, PartialEq, Eq)] pub enum Filter { @@ -420,16 +419,22 @@ fn find_function_in_commit_with_filetype( } } Language::All => { - if file.ends_with(".rs") - || file.ends_with(".py") - // TODO: use cfg!() macro to check if c_lang is enabled - || file.ends_with(".c") - || file.ends_with(".h") - // TODO: use cfg!() macro to check if unstable is enabled - || file.ends_with(".go") - || file.ends_with(".rb") - { - files.push(file); + cfg_if::cfg_if! { + if #[cfg(feature = "c_lang")] { + if file.ends_with(".c") || file.ends_with(".h") { + files.push(file); + } + } + else if #[cfg(feature = "unstable")] { + if file.ends_with(".go") { + files.push(file); + } + } + else { + if file.ends_with(".py") || file.ends_with(".rs") || file.ends_with(".rb") { + files.push(file); + } + } } } } From 64349bfa97d113d6133a5210d7d68f9e93aa4bdd Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Sun, 23 Oct 2022 00:38:14 -0400 Subject: [PATCH 070/172] removed some places where code could panic, cleaned up a drop --- git-function-history-lib/src/languages/go.rs | 35 +++++---- .../src/languages/java.rs | 5 +- .../src/languages/ruby.rs | 22 +++--- git-function-history-lib/src/lib.rs | 77 +++++++++---------- 4 files changed, 69 insertions(+), 70 deletions(-) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index 36a940a1..5a886ee7 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -1,6 +1,5 @@ -use std::{collections::HashMap, error::Error, fmt}; - use crate::impl_function_trait; +use std::{error::Error, fmt}; use super::FunctionTrait; @@ -60,23 +59,18 @@ pub(crate) fn find_function_in_file( file_contents: &str, name: &str, ) -> Result, Box> { - // TODO: progate errors back in clusre intead of paicking with excpet let parsed_file = gosyn::parse_source(file_contents) .map_err(|e| format!("{:?}", e))? .decl; - Ok(parsed_file + let parsed = parsed_file .into_iter() .filter_map(|decl| match decl { gosyn::ast::Declaration::Function(func) => { if func.name.name == name { - let mut lines = ( - func.name.pos, - func.body - .as_ref() - .expect("no body found for function") - .pos - .1, - ); + let mut lines = match func.body.as_ref() { + Some(body) => (func.name.pos, body.pos.1), + None => return None, + }; match func.recv { Some(recv) => { lines.0 = recv.pos(); @@ -84,8 +78,8 @@ pub(crate) fn find_function_in_file( None => {} } lines.0 = file_contents[..lines.0] - .rfind("func") - .expect("could not find 'func' keyword before function"); + .rfind("func")?; + for i in &func.docs { if i.pos < lines.0 { lines.0 = i.pos; @@ -120,7 +114,12 @@ pub(crate) fn find_function_in_file( .params .list .iter() - .map(|p| &p.tag.as_ref().expect("uknown plz report bug idk").value) + .filter_map(|p| { + Some(&p.tag + .as_ref() + ? + .value) + }) .map(|x| x.to_string()) .collect(); let returns = Some( @@ -151,7 +150,11 @@ pub(crate) fn find_function_in_file( } _ => None, }) - .collect::>()) + .collect::>(); + if parsed.is_empty() { + return Err(format!("could not find function {} in file", name).into()); + } + Ok(parsed) } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/git-function-history-lib/src/languages/java.rs b/git-function-history-lib/src/languages/java.rs index 0689cfa7..3929403d 100644 --- a/git-function-history-lib/src/languages/java.rs +++ b/git-function-history-lib/src/languages/java.rs @@ -68,6 +68,5 @@ mod java_test { } "#; let function = find_function_in_file(file_contents, "main").unwrap(); - - } - } \ No newline at end of file + } +} diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index fb6d9b52..97a498e1 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -98,9 +98,11 @@ pub(crate) fn find_function_in_file( }; let top = Loc { begin: c.expression_l.begin, - end: c.body.as_ref().map_or(0, |b| b.expression().begin) + end: c.body.as_ref().map_or(0, |b| b.expression().begin), }; - let mut top = top.source(&parsed.input).unwrap_to_error("Failed to get source")?; + let mut top = top + .source(&parsed.input) + .unwrap_to_error("Failed to get source")?; top = top.trim_end().to_string(); top.push_str("\n"); let mut starts = start_line; @@ -108,12 +110,13 @@ pub(crate) fn find_function_in_file( name: parser_class_name(c), line: (start_line, end_line), superclass: None, - top: top.lines() - .map(|l| { - starts += 1; - format!("{}: {}\n", starts, l,) - }) - .collect(), + top: top + .lines() + .map(|l| { + starts += 1; + format!("{}: {}\n", starts, l,) + }) + .collect(), bottom: format!( "{end_line}: {}", loc_end @@ -172,8 +175,6 @@ pub(crate) fn find_function_in_file( .collect() } - - fn get_functions_from_node( node: &lib_ruby_parser::Node, class: &Option, @@ -232,7 +233,6 @@ fn parse_args_from_node(node: &lib_ruby_parser::Node) -> Vec { vec![] } - fn parser_class_name(class: &Class) -> String { match class.name.as_ref() { lib_ruby_parser::Node::Const(constant) => constant.name.clone(), diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 9793246f..7a8f22cf 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -14,7 +14,6 @@ clippy::return_self_not_must_use )] pub mod languages; -use cfg_if::cfg_if; /// Different types that can extracted from the result of `get_function_history`. pub mod types; @@ -389,56 +388,54 @@ fn find_function_in_commit_with_filetype( files.push(file); } } - FileFilterType::None => { - match langs { - #[cfg(feature = "c_lang")] - Language::C => { - if file.ends_with(".c") || file.ends_with(".h") { - files.push(file); - } + FileFilterType::None => match langs { + #[cfg(feature = "c_lang")] + Language::C => { + if file.ends_with(".c") || file.ends_with(".h") { + files.push(file); } - #[cfg(feature = "unstable")] - Language::Go => { - if file.ends_with(".go") { - files.push(file); - } + } + #[cfg(feature = "unstable")] + Language::Go => { + if file.ends_with(".go") { + files.push(file); } - Language::Python => { - if file.ends_with(".py") { - files.push(file); - } + } + Language::Python => { + if file.ends_with(".py") { + files.push(file); } - Language::Rust => { - if file.ends_with(".rs") { - files.push(file); - } + } + Language::Rust => { + if file.ends_with(".rs") { + files.push(file); } - Language::Ruby => { - if file.ends_with(".rb") { - files.push(file); - } + } + Language::Ruby => { + if file.ends_with(".rb") { + files.push(file); } - Language::All => { - cfg_if::cfg_if! { - if #[cfg(feature = "c_lang")] { - if file.ends_with(".c") || file.ends_with(".h") { - files.push(file); - } + } + Language::All => { + cfg_if::cfg_if! { + if #[cfg(feature = "c_lang")] { + if file.ends_with(".c") || file.ends_with(".h") { + files.push(file); } - else if #[cfg(feature = "unstable")] { - if file.ends_with(".go") { - files.push(file); - } + } + else if #[cfg(feature = "unstable")] { + if file.ends_with(".go") { + files.push(file); } - else { - if file.ends_with(".py") || file.ends_with(".rs") || file.ends_with(".rb") { - files.push(file); - } + } + else { + if file.ends_with(".py") || file.ends_with(".rs") || file.ends_with(".rb") { + files.push(file); } } } } - } + }, } } let err = "no function found".to_string(); From f8bfc8321732da0e68e7bf39f1180f3b44005ff4 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 23 Oct 2022 08:06:05 -0400 Subject: [PATCH 071/172] more javas stuff --- .../src/languages/java.rs | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/git-function-history-lib/src/languages/java.rs b/git-function-history-lib/src/languages/java.rs index 0689cfa7..5c62c98c 100644 --- a/git-function-history-lib/src/languages/java.rs +++ b/git-function-history-lib/src/languages/java.rs @@ -1,5 +1,7 @@ use std::fmt; +use javaparser::parse::tree::CompilationUnit; + #[derive(Debug, Clone, PartialEq, Eq)] pub struct JavaFunction { pub name: String, @@ -47,13 +49,30 @@ pub struct JavaClass { pub(crate) fn find_function_in_file( file_contents: &str, name: &str, -) -> Result { +) -> Result, String> { let file = javaparser::parse::apply(file_contents, "").map_err(|_| "Parse error")?; - let parsed = file.unit.clone(); - println!("{:#?}", file); + let parsed = file.unit.clone().items; + println!("{:#?}", parsed); Err("Not implemented".to_string()) } +fn extract_methods_from_compilation_unit( + unit: &CompilationUnit<'_>, + name: &str, +) -> Result, String> { + let mut methods = Vec::new(); + for item in &unit.items { + match item { + javaparser::parse::tree::CompilationUnitItem::Class(_) => todo!(), + javaparser::parse::tree::CompilationUnitItem::Interface(_) => todo!(), + javaparser::parse::tree::CompilationUnitItem::Annotation(_) => todo!(), + javaparser::parse::tree::CompilationUnitItem::Enum(_) => todo!(), + } + } + Ok(methods) + } + + #[cfg(test)] mod java_test { use super::*; @@ -70,4 +89,4 @@ mod java_test { let function = find_function_in_file(file_contents, "main").unwrap(); } - } \ No newline at end of file + } From ef7b470b1849413ca30fb55298b579ac80702685 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 23 Oct 2022 10:36:22 -0400 Subject: [PATCH 072/172] renamed some filters, and made some filters work better --- git-function-history-lib/src/languages/mod.rs | 10 +- .../src/languages/python.rs | 4 +- .../src/languages/ruby.rs | 6 +- .../src/languages/rust.rs | 4 +- git-function-history-lib/src/lib.rs | 39 ++++- git-function-history-lib/src/types.rs | 135 +++++++++++++++--- 6 files changed, 164 insertions(+), 34 deletions(-) diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 29733fe7..59e7c822 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -31,17 +31,17 @@ pub enum Language { #[derive(Debug, Clone, PartialEq, Eq)] pub enum LanguageFilter { /// python filter - Python(python::Filter), + Python(python::PythonFilter), /// rust filter - Rust(rust::Filter), + Rust(rust::RustFilter), #[cfg(feature = "c_lang")] /// c filter - C(c::Filter), + C(c::CFilter), #[cfg(feature = "unstable")] /// go filter - Go(go::Filter), + Go(go::GoFilter), /// ruby filter - Ruby(ruby::Filter), + Ruby(ruby::RubyFilter), } impl Language { diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index d150896e..caa48c7b 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -271,7 +271,7 @@ fn get_functions<'a>( } } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Filter { +pub enum PythonFilter { /// when you want to filter by function that are in a specific class FunctionInClass(String), /// when you want filter by a function that has a parent function of a specific name @@ -284,7 +284,7 @@ pub enum Filter { FunctionWithDecorator(String), } -impl Filter { +impl PythonFilter { pub fn matches(&self, function: &PythonFunction) -> bool { match self { Self::FunctionInClass(class) => { diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 97a498e1..5a143e8a 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -104,7 +104,7 @@ pub(crate) fn find_function_in_file( .source(&parsed.input) .unwrap_to_error("Failed to get source")?; top = top.trim_end().to_string(); - top.push_str("\n"); + top.push('\n'); let mut starts = start_line; Some(RubyClass { name: parser_class_name(c), @@ -260,11 +260,11 @@ impl FunctionTrait for RubyFunction { } } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Filter { +pub enum RubyFilter { FunctionInLines((usize, usize)), } -impl Filter { +impl RubyFilter { pub const fn matches(&self, function: &RubyFunction) -> bool { match self { Self::FunctionInLines((start, end)) => { diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 098df04b..52b78ca1 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -457,7 +457,7 @@ fn get_doc_comments_and_attrs(block: &T) -> (Vec, Vec ) } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Filter { +pub enum RustFilter { /// when you want to filter by function that are in a specific block (impl, trait, extern) FunctionInBlock(BlockType), /// when you want filter by a function that has a parent function of a specific name @@ -476,7 +476,7 @@ pub enum Filter { FunctionWithAttribute(String), } -impl Filter { +impl RustFilter { pub fn matches(&self, function: &RustFunction) -> bool { match self { Self::FunctionInBlock(block_type) => function diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 7a8f22cf..8444b3f4 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -546,7 +546,7 @@ impl UnwrapToError for Option { mod tests { use chrono::Utc; - use crate::languages::FileTrait; + use crate::languages::{rust::BlockType, FileTrait}; use super::*; #[test] @@ -743,4 +743,41 @@ mod tests { } assert!(output.is_ok()); } + + #[test] + fn filter_by_param_rust() { + // search for rust functions + let mut now = Utc::now(); + let output = get_function_history!(name = "empty_test", language = Language::Rust); + let mut after = Utc::now() - now; + println!("time taken to search: {}", after.num_seconds()); + let output = match output { + Ok(result) => result, + Err(e) => panic!("{}", e), + }; + now = Utc::now(); + let new_output = output.filter_by(&Filter::PLFilter(LanguageFilter::Rust( + rust::RustFilter::FunctionWithParameterType(String::from("String")) + ))); + after = Utc::now() - now; + println!("time taken to filter {}", after.num_seconds()); + match &new_output { + Ok(res) => { + println!("{}", res) + } + Err(e) => println!("{e}"), + } + let new_output = output.filter_by(&Filter::PLFilter(LanguageFilter::Rust( + rust::RustFilter::FunctionInBlock(BlockType::Extern), + ))); + after = Utc::now() - now; + println!("time taken to filter {}", after.num_seconds()); + match &new_output { + Ok(res) => { + println!("{}", res) + } + Err(e) => println!("{e}"), + } + assert!(new_output.is_ok()) + } } diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 2e1641c0..9e29e6b9 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -211,15 +211,31 @@ impl Commit { #[cfg(not(feature = "parallel"))] let t = self.files.iter(); let vec: Vec<_> = t - .filter(|f| match filter { - Filter::FileAbsolute(file) => f.get_file_name() == *file, - Filter::FileRelative(file) => f.get_file_name().ends_with(file), - Filter::Directory(dir) => f.get_file_name().contains(dir), - Filter::FunctionInLines(..) | Filter::PLFilter(_) => f.filter_by(filter).is_ok(), - Filter::None => true, - _ => false, + .filter_map(|f| match filter { + Filter::FileAbsolute(file) => { + if f.get_file_name() == *file { + Some(f.clone()) + } else { + None + } + } + Filter::FileRelative(file) => { + if f.get_file_name().ends_with(file) { + Some(f.clone()) + } else { + None + } + } + Filter::Directory(dir) => { + if f.get_file_name().contains(dir) { + Some(f.clone()) + } else { + None + } + } + Filter::FunctionInLines(..) | Filter::PLFilter(_) => f.filter_by(filter).ok(), + _ => None, }) - .cloned() .collect(); if vec.is_empty() { @@ -355,38 +371,115 @@ impl FunctionHistory { /// /// history.filter_by(&Filter::Directory("app".to_string())).unwrap(); /// ``` + // pub fn filter_by(&self, filter: &Filter) -> Result> { + // #[cfg(feature = "parallel")] + // let t = self.commit_history.par_iter(); + // #[cfg(not(feature = "parallel"))] + // let t = self.commit_history.iter(); + // let vec: Vec = t + // .filter(|f| match filter { + // Filter::FunctionInLines(..) + // | Filter::Directory(_) + // | Filter::FileAbsolute(_) + // | Filter::PLFilter(_) + // | Filter::FileRelative(_) => f.filter_by(filter).is_ok(), + // Filter::CommitHash(commit_hash) => &f.commit_hash == commit_hash, + // Filter::Date(date) => &f.date.to_rfc2822() == date, + // Filter::DateRange(start, end) => { + // let start = match DateTime::parse_from_rfc2822(start) { + // Ok(date) => date, + // Err(_) => return false, + // }; + // let end = match DateTime::parse_from_rfc2822(end) { + // Ok(date) => date, + // Err(_) => return false, + // }; + // f.date >= start || f.date <= end + // } + // Filter::Author(author) => &f.author == author, + // Filter::AuthorEmail(email) => &f.email == email, + // Filter::Message(message) => f.message.contains(message), + // Filter::None => true, + // }) + // .cloned() + // .collect(); + + // if vec.is_empty() { + // return Err("No history found for the filter")?; + // } + // Ok(Self { + // commit_history: vec, + // name: self.name.clone(), + // current_pos: 0, + // current_iter_pos: 0, + // }) + // } + pub fn filter_by(&self, filter: &Filter) -> Result> { #[cfg(feature = "parallel")] let t = self.commit_history.par_iter(); #[cfg(not(feature = "parallel"))] let t = self.commit_history.iter(); let vec: Vec = t - .filter(|f| match filter { + .filter_map(|f| match filter { Filter::FunctionInLines(..) | Filter::Directory(_) | Filter::FileAbsolute(_) | Filter::PLFilter(_) - | Filter::FileRelative(_) => f.filter_by(filter).is_ok(), - Filter::CommitHash(commit_hash) => &f.commit_hash == commit_hash, - Filter::Date(date) => &f.date.to_rfc2822() == date, + | Filter::FileRelative(_) => f.filter_by(filter).ok(), + Filter::CommitHash(commit_hash) => { + if &f.commit_hash == commit_hash { + Some(f.clone()) + } else { + None + } + } + + Filter::Date(date) => { + if &f.date.to_rfc2822() == date { + Some(f.clone()) + } else { + None + } + } Filter::DateRange(start, end) => { let start = match DateTime::parse_from_rfc2822(start) { Ok(date) => date, - Err(_) => return false, + Err(_) => return None, }; let end = match DateTime::parse_from_rfc2822(end) { Ok(date) => date, - Err(_) => return false, + Err(_) => return None, }; - f.date >= start || f.date <= end + if f.date >= start || f.date <= end { + Some(f.clone()) + } else { + None + } } - - Filter::Author(author) => &f.author == author, - Filter::AuthorEmail(email) => &f.email == email, - Filter::Message(message) => f.message.contains(message), - Filter::None => true, + Filter::Author(author) => { + if &f.author == author { + Some(f.clone()) + } else { + None + } + } + Filter::AuthorEmail(email) => { + if &f.email == email { + Some(f.clone()) + } else { + None + } + } + Filter::Message(message) => { + if f.message.contains(message) { + Some(f.clone()) + } else { + None + } + } + Filter::None => None, }) - .cloned() .collect(); if vec.is_empty() { From 37bbb533a5d7e1c1024a9ab6815a586814cb3141 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 23 Oct 2022 16:55:27 -0400 Subject: [PATCH 073/172] fixed some optinal stuff --- git-function-history-lib/src/languages/c.rs | 4 +-- git-function-history-lib/src/languages/go.rs | 28 +++++++++----------- git-function-history-lib/src/types.rs | 24 ++++++++--------- 3 files changed, 26 insertions(+), 30 deletions(-) diff --git a/git-function-history-lib/src/languages/c.rs b/git-function-history-lib/src/languages/c.rs index 4a7183d5..d8829b45 100644 --- a/git-function-history-lib/src/languages/c.rs +++ b/git-function-history-lib/src/languages/c.rs @@ -73,14 +73,14 @@ pub(crate) fn find_function_in_file( todo!("find_function_in_commit") } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Filter { +pub enum CFilter { /// when you want filter by a function that has a parent function of a specific name FunctionWithParent(String), /// when you want to filter by a function that has a has a specific return type FunctionWithReturnType(String), } -impl Filter { +impl CFilter { pub fn matches(&self, function: &CFunction) -> bool { match self { Self::FunctionWithParent(parent) => function diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index 2f7f7752..99d62d98 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -71,11 +71,8 @@ pub(crate) fn find_function_in_file( Some(body) => (func.name.pos, body.pos.1), None => return None, }; - match func.recv { - Some(recv) => { - lines.0 = recv.pos(); - } - None => {} + if let Some(recv) = func.recv { + lines.0 = recv.pos(); } lines.0 = file_contents[..lines.0].rfind("func")?; @@ -84,7 +81,7 @@ pub(crate) fn find_function_in_file( lines.0 = i.pos; } } - let body = file_contents[lines.0..lines.1 + 1].to_string(); + let body = file_contents[lines.0..=lines.1].to_string(); let mut start_line = 0; for i in file_contents.chars().enumerate() { if i.1 == '\n' { @@ -114,7 +111,7 @@ pub(crate) fn find_function_in_file( .list .iter() .filter_map(|p| Some(&p.tag.as_ref()?.value)) - .map(|x| x.to_string()) + .map(std::string::ToString::to_string) .collect(); let returns = Some( func.typ @@ -124,8 +121,8 @@ pub(crate) fn find_function_in_file( .map(|p| { p.name .iter() - .map(|x| &x.clone().name) - .map(|x| x.to_string()) + .map(|x| &x.name) + .map(std::string::ToString::to_string) .collect::() }) .collect(), @@ -152,24 +149,23 @@ pub(crate) fn find_function_in_file( } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum Filter { +pub enum GoFilter { FunctionWithParameter(String), FunctionWithReturnType(String), FunctionInLines(usize, usize), } -impl Filter { +impl GoFilter { pub fn matches(&self, func: &GoFunction) -> bool { match self { - Filter::FunctionWithParameter(param) => { + Self::FunctionWithParameter(param) => { func.parameters.iter().any(|x| x.contains(param)) } - Filter::FunctionWithReturnType(ret) => func + Self::FunctionWithReturnType(ret) => func .returns .as_ref() - .map(|x| x.contains(ret)) - .unwrap_or(false), - Filter::FunctionInLines(start, end) => { + .map_or(false, |x| x.contains(ret)), + Self::FunctionInLines(start, end) => { let (s, e) = func.get_total_lines(); s >= *start && e <= *end } diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 9e29e6b9..29fc43f2 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -36,9 +36,9 @@ impl FileTrait for FileType { Self::Rust(file) => file.get_file_name(), Self::Python(file) => file.get_file_name(), #[cfg(feature = "c_lang")] - FileType::C(file) => file.get_file_name(), + Self::C(file) => file.get_file_name(), #[cfg(feature = "unstable")] - FileType::Go(file) => file.get_file_name(), + Self::Go(file) => file.get_file_name(), Self::Ruby(file) => file.get_file_name(), } } @@ -47,9 +47,9 @@ impl FileTrait for FileType { Self::Rust(file) => file.get_functions(), Self::Python(file) => file.get_functions(), #[cfg(feature = "c_lang")] - FileType::C(file) => file.get_functions(), + Self::C(file) => file.get_functions(), #[cfg(feature = "unstable")] - FileType::Go(file) => file.get_functions(), + Self::Go(file) => file.get_functions(), Self::Ruby(file) => file.get_functions(), } } @@ -65,14 +65,14 @@ impl FileTrait for FileType { Ok(Self::Python(filtered)) } #[cfg(feature = "c_lang")] - FileType::C(file) => { + Self::C(file) => { let filtered = file.filter_by(filter)?; - Ok(FileType::C(filtered)) + Ok(Self::C(filtered)) } #[cfg(feature = "unstable")] - FileType::Go(file) => { + Self::Go(file) => { let filtered = file.filter_by(filter)?; - Ok(FileType::Go(filtered)) + Ok(Self::Go(filtered)) } Self::Ruby(file) => { let filtered = file.filter_by(filter)?; @@ -86,9 +86,9 @@ impl FileTrait for FileType { Self::Rust(file) => file.get_current(), Self::Python(file) => file.get_current(), #[cfg(feature = "c_lang")] - FileType::C(file) => file.get_current(), + Self::C(file) => file.get_current(), #[cfg(feature = "unstable")] - FileType::Go(file) => file.get_current(), + Self::Go(file) => file.get_current(), Self::Ruby(file) => file.get_current(), } } @@ -100,9 +100,9 @@ impl fmt::Display for FileType { Self::Rust(file) => write!(f, "{}", file), Self::Python(file) => write!(f, "{}", file), #[cfg(feature = "c_lang")] - FileType::C(file) => write!(f, "{}", file), + Self::C(file) => write!(f, "{}", file), #[cfg(feature = "unstable")] - FileType::Go(file) => write!(f, "{}", file), + Self::Go(file) => write!(f, "{}", file), Self::Ruby(file) => write!(f, "{}", file), } } From fd06e3317b84139c7a565c0aa38726a634cd21d5 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 23 Oct 2022 21:28:02 -0400 Subject: [PATCH 074/172] tui: shortend filter loc --- cargo-function-history/src/app/mod.rs | 189 +++++------------- git-function-history-lib/src/languages/mod.rs | 7 +- 2 files changed, 57 insertions(+), 139 deletions(-) diff --git a/cargo-function-history/src/app/mod.rs b/cargo-function-history/src/app/mod.rs index 0b509155..324de24a 100644 --- a/cargo-function-history/src/app/mod.rs +++ b/cargo-function-history/src/app/mod.rs @@ -174,140 +174,6 @@ impl App { let mut iter = iter.trim().split(' '); match iter.next() { Some(cmd) => match cmd { - "filter" => { - if let CommandResult::History(_) = &self.cmd_output { - self.status = Status::Loading; - if let Some(filter) = iter.next() { - let filter = match filter { - "date" => { - if let Some(date) = iter.next() { - let date = date.replace('_', " "); - Some(Filter::Date(date)) - } else { - self.status = Status::Error("No date given".to_string()); - None - } - } - "commit" => { - if let Some(commit) = iter.next() { - Some(Filter::CommitHash(commit.to_string())) - } else { - self.status = Status::Error("No commit given".to_string()); - None - } - } - "parent" => { - if let Some(_parent) = iter.next() { - // Some(Filter::FunctionWithParent(parent.to_string())) - None - } else { - self.status = - Status::Error("No parent function given".to_string()); - None - } - } - // "block" => { - // if let Some(block) = iter.next() { - // Some(Filter::FunctionInBlock(BlockType::from_string(block))) - // } else { - // self.status = - // Status::Error("No block type given".to_string()); - // None - // } - // } - "date-range" => { - if let Some(start) = iter.next() { - if let Some(end) = iter.next() { - // remove all - from the date - let start = start.replace('_', " "); - let end = end.replace('_', " "); - Some(Filter::DateRange(start, end)) - } else { - self.status = - Status::Error("No end date given".to_string()); - None - } - } else { - self.status = - Status::Error("No start date given".to_string()); - None - } - } - "line-range" => { - if let Some(start) = iter.next() { - if let Some(end) = iter.next() { - let start = match start.parse::() { - Ok(x) => x, - Err(e) => { - self.status = Status::Error(format!("{}", e)); - return; - } - }; - let end = match end.parse::() { - Ok(x) => x, - Err(e) => { - self.status = Status::Error(format!("{}", e)); - return; - } - }; - Some(Filter::FunctionInLines(start, end)) - } else { - self.status = - Status::Error("No end line given".to_string()); - None - } - } else { - self.status = - Status::Error("No start line given".to_string()); - None - } - } - "file-absolute" => { - if let Some(file) = iter.next() { - Some(Filter::FileAbsolute(file.to_string())) - } else { - self.status = Status::Error("No file given".to_string()); - None - } - } - "file-relative" => { - if let Some(file) = iter.next() { - Some(Filter::FileRelative(file.to_string())) - } else { - self.status = Status::Error("No file given".to_string()); - None - } - } - "directory" => { - if let Some(dir) = iter.next() { - Some(Filter::Directory(dir.to_string())) - } else { - self.status = - Status::Error("No directory given".to_string()); - None - } - } - _ => { - self.status = Status::Error("Invalid filter".to_string()); - None - } - }; - if let Some(filter) = filter { - self.channels - .0 - .send(FullCommand::Filter(FilterType { - thing: self.cmd_output.clone(), - filter, - })) - .unwrap(); - } - } else { - self.status = Status::Error("No filter given".to_string()); - } - } else if iter.next().is_some() { - self.status = Status::Error("no filters available".to_string()); - } - } "search" => { // check for a function name if let Some(name) = iter.next() { @@ -349,7 +215,6 @@ impl App { } }; } - _ => { self.status = Status::Error(format!("Invalid search {}", i[0])); return; @@ -365,6 +230,60 @@ impl App { self.status = Status::Error("No function name given".to_string()); } } + "filter" => { + self.status = Status::Loading; + let mut filter = Filter::None; + for i in iter.collect::>().windows(2) { + match i { + ["date", date] => { + filter = Filter::Date(date.to_string()); + } + ["commit", commit] => { + filter = Filter::CommitHash(commit.to_string()); + } + ["date range", start, end] => { + filter = Filter::DateRange(start.to_string(), end.to_string()); + } + ["line range", start, end] => { + let start = match start.parse::() { + Ok(x) => x, + Err(e) => { + self.status = Status::Error(format!("{}", e)); + return; + } + }; + let end = match end.parse::() { + Ok(x) => x, + Err(e) => { + self.status = Status::Error(format!("{}", e)); + return; + } + }; + filter = Filter::FunctionInLines(start, end); + } + ["file absolute", file] => { + filter = Filter::FileAbsolute(file.to_string()); + } + ["file relative", file] => { + filter = Filter::FileRelative(file.to_string()); + } + ["directory", dir] => { + filter = Filter::Directory(dir.to_string()); + } + _ => { + self.status = Status::Error(format!("Invalid filter {}", i[0])); + return; + } + } + } + self.channels + .0 + .send(FullCommand::Filter(FilterType { + thing: self.cmd_output.clone(), + filter, + })) + .unwrap(); + } "list" => { self.status = Status::Loading; let list = match iter.next() { diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 59e7c822..b9a578bc 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -3,7 +3,7 @@ use std::{ error::Error, fmt::{self, Display}, }; -// TODO: lisp/scheme js go(https://docs.rs/gosyn/latest/gosyn/) ruby(https://docs.rs/lib-ruby-parser/latest/lib_ruby_parser/) java?(https://github.com/tanin47/javaparser.rs) php?(https://docs.rs/tagua-parser/0.1.0/tagua_parser/) +// TODO: lisp/scheme js, java?(https://github.com/tanin47/javaparser.rs) php?(https://docs.rs/tagua-parser/0.1.0/tagua_parser/) use self::{python::PythonFunction, ruby::RubyFunction, rust::RustFunction}; #[cfg(feature = "c_lang")] @@ -154,7 +154,6 @@ pub fn fmt_with_context( Ok(()) } -// functiontrait is not object safe, so we can't implement it for a trait object ie box pub trait FileTrait: fmt::Debug + fmt::Display { fn get_file_name(&self) -> String; fn get_functions(&self) -> Vec>; @@ -164,7 +163,7 @@ pub trait FileTrait: fmt::Debug + fmt::Display { fn get_current(&self) -> Option>; } -// make a macro that generates the code for the different languages +// macro that generates the code for the different languages macro_rules! make_file { ($name:ident, $function:ident, $filtername:ident) => { #[derive(Debug, Clone)] @@ -262,7 +261,7 @@ make_file!(CFile, CFunction, C); make_file!(GoFile, GoFunction, Go); make_file!(RubyFile, RubyFunction, Ruby); -// make macro that auto genertes the test parse__file_time +// macro that auto genertes the test parse__file_time macro_rules! make_file_time_test { ($name:ident, $extname:ident, $function:ident) => { #[test] From 5fc408c499454c9f0e684a0a4ae643b1657ecd37 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Mon, 24 Oct 2022 01:28:35 +0000 Subject: [PATCH 075/172] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f3f8693..15bd04dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ All notable changes to this project will be documented in this file. ### Tui - Saving search history to a file now +- Shortend filter loc ## [2.1.0] - 2022-09-28 From 08645b74cf641a2827d22c566d54029370a4ee4b Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 23 Oct 2022 22:42:14 -0400 Subject: [PATCH 076/172] tui: search/filters are fixed was not working b/c of using window(2) also command history starts from last entered command --- cargo-function-history/src/app/mod.rs | 83 +++++++++++++++++--- git-function-history-lib/src/languages/go.rs | 9 +-- git-function-history-lib/src/lib.rs | 2 +- 3 files changed, 75 insertions(+), 19 deletions(-) diff --git a/cargo-function-history/src/app/mod.rs b/cargo-function-history/src/app/mod.rs index 324de24a..e722bb25 100644 --- a/cargo-function-history/src/app/mod.rs +++ b/cargo-function-history/src/app/mod.rs @@ -64,8 +64,8 @@ impl App { let mut history = String::new(); file.read_to_string(&mut history) .expect("Failed to read history file"); - let history = history.split('\n').map(|s| s.to_string()).collect(); - + let history: Vec = history.split('\n').map(|s| s.to_string()).collect(); + // let history_index = history.len(); let actions = vec![ Action::Quit, Action::TextEdit, @@ -87,8 +87,8 @@ impl App { body_height: 0, channels, status, + history_index: history.len() - 1, history, - history_index: 0, } } @@ -174,6 +174,7 @@ impl App { let mut iter = iter.trim().split(' '); match iter.next() { Some(cmd) => match cmd { + // TODO: add author, email, message "search" => { // check for a function name if let Some(name) = iter.next() { @@ -182,24 +183,48 @@ impl App { let mut file = FileFilterType::None; let mut filter = Filter::None; let mut lang = Language::All; - for i in iter.collect::>().windows(2) { + log::debug!( + "searching for {:?}", + iter.clone().collect::>().windows(2) + ); + for i in &mut iter.clone().collect::>().windows(2) { match i { ["relative", filepath] => { + log::trace!("relative file: {}", filepath); file = FileFilterType::Relative(filepath.to_string()); } ["absolute", filepath] => { + log::trace!("absolute file: {}", filepath); file = FileFilterType::Absolute(filepath.to_string()); } ["date", date] => { + log::trace!("date: {}", date); filter = Filter::Date(date.to_string()); } ["commit", commit] => { + log::trace!("commit: {}", commit); filter = Filter::CommitHash(commit.to_string()); } - ["date range", start, end] => { + ["directory", dir] => { + log::trace!("directory: {}", dir); + file = FileFilterType::Directory(dir.to_string()); + } + ["date-range", pos] => { + log::trace!("date range: {}", pos); + let (start, end) = match pos.split_once("..") { + Some((start, end)) => (start, end), + None => { + self.status = Status::Error( + "Invalid date range, expected start..end" + .to_string(), + ); + return; + } + }; filter = Filter::DateRange(start.to_string(), end.to_string()); } ["language", language] => { + log::trace!("language: {}", language); lang = match language { &"rust" => Language::Rust, &"python" => Language::Python, @@ -216,12 +241,19 @@ impl App { }; } _ => { - self.status = Status::Error(format!("Invalid search {}", i[0])); + log::debug!("invalid arg: {:?}", i); + self.status = Status::Error(format!("Invalid search {:?}", i)); return; } } } - + if iter.clone().count() > 0 { + self.status = Status::Error(format!( + "Invalid search, command: {:?} missing args", + iter.collect::>() + )); + return; + } self.channels .0 .send(FullCommand::Search(name.to_string(), file, filter, lang)) @@ -233,7 +265,7 @@ impl App { "filter" => { self.status = Status::Loading; let mut filter = Filter::None; - for i in iter.collect::>().windows(2) { + for i in &mut iter.clone().collect::>().windows(2) { match i { ["date", date] => { filter = Filter::Date(date.to_string()); @@ -241,10 +273,29 @@ impl App { ["commit", commit] => { filter = Filter::CommitHash(commit.to_string()); } - ["date range", start, end] => { + ["date-range", pos] => { + let (start, end) = match pos.split_once("..") { + Some((start, end)) => (start, end), + None => { + self.status = Status::Error( + "Invalid date range, expected start..end".to_string(), + ); + return; + } + }; filter = Filter::DateRange(start.to_string(), end.to_string()); } - ["line range", start, end] => { + ["line-range", pos] => { + // get the start and end by splitting the pos by: .. + let (start, end) = match pos.split_once("..") { + Some((start, end)) => (start, end), + None => { + self.status = Status::Error( + "Invalid line range, expected start..end".to_string(), + ); + return; + } + }; let start = match start.parse::() { Ok(x) => x, Err(e) => { @@ -261,10 +312,10 @@ impl App { }; filter = Filter::FunctionInLines(start, end); } - ["file absolute", file] => { + ["file-absolute", file] => { filter = Filter::FileAbsolute(file.to_string()); } - ["file relative", file] => { + ["file-relative", file] => { filter = Filter::FileRelative(file.to_string()); } ["directory", dir] => { @@ -276,6 +327,14 @@ impl App { } } } + if iter.clone().count() > 0 { + self.status = Status::Error(format!( + "Invalid filter, command: {:?} missing args", + iter.collect::>() + )); + return; + } + self.channels .0 .send(FullCommand::Filter(FilterType { diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index 99d62d98..4971a824 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -158,13 +158,10 @@ pub enum GoFilter { impl GoFilter { pub fn matches(&self, func: &GoFunction) -> bool { match self { - Self::FunctionWithParameter(param) => { - func.parameters.iter().any(|x| x.contains(param)) + Self::FunctionWithParameter(param) => func.parameters.iter().any(|x| x.contains(param)), + Self::FunctionWithReturnType(ret) => { + func.returns.as_ref().map_or(false, |x| x.contains(ret)) } - Self::FunctionWithReturnType(ret) => func - .returns - .as_ref() - .map_or(false, |x| x.contains(ret)), Self::FunctionInLines(start, end) => { let (s, e) = func.get_total_lines(); s >= *start && e <= *end diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 8444b3f4..58c907ee 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -757,7 +757,7 @@ mod tests { }; now = Utc::now(); let new_output = output.filter_by(&Filter::PLFilter(LanguageFilter::Rust( - rust::RustFilter::FunctionWithParameterType(String::from("String")) + rust::RustFilter::FunctionWithParameterType(String::from("String")), ))); after = Utc::now() - now; println!("time taken to filter {}", after.num_seconds()); From 2c9255487286ecc73774248cc9a5b2318fee7ceb Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Mon, 24 Oct 2022 02:42:49 +0000 Subject: [PATCH 077/172] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15bd04dd..9b8a7efb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ All notable changes to this project will be documented in this file. - Saving search history to a file now - Shortend filter loc +- Search/filters are fixed was not working b/c of using window(2) ## [2.1.0] - 2022-09-28 From 8a8ea83668f1209481dfcbaa40bd282826228b43 Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Mon, 24 Oct 2022 12:33:35 -0400 Subject: [PATCH 078/172] docs --- git-function-history-lib/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 58c907ee..ba8efbd2 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -88,7 +88,7 @@ pub enum Filter { ///
/// If its a relative it will look for a that ends with the name of the file. ///
-/// If its none it will look for all files in the repo that end in .rs. +/// If its none it will look for all files in the repo that end in supported files (depends on features) /// Note: using `FilteType::None` will take a long time to run (especially if you no filters). ///
/// It will then go through the file and find all the functions and blocks in the file. @@ -97,7 +97,7 @@ pub enum Filter { ///
/// It will then return a `FunctionHistory` struct with all the commits with files that have functions that match the name. ///
-/// If no histoy is is available it will error out with `no history found`. +/// If no histoy is is available it will error out with `no history found`, and possibly a reason why. /// /// # examples /// From 1db0793f476dd84fb4f9d2c085992202ddf95ded Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 24 Oct 2022 12:45:10 -0400 Subject: [PATCH 079/172] tui: added more filters --- cargo-function-history/src/app/mod.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/cargo-function-history/src/app/mod.rs b/cargo-function-history/src/app/mod.rs index e722bb25..8525a35c 100644 --- a/cargo-function-history/src/app/mod.rs +++ b/cargo-function-history/src/app/mod.rs @@ -174,7 +174,6 @@ impl App { let mut iter = iter.trim().split(' '); match iter.next() { Some(cmd) => match cmd { - // TODO: add author, email, message "search" => { // check for a function name if let Some(name) = iter.next() { @@ -240,6 +239,19 @@ impl App { } }; } + ["author", author] => { + log::trace!("author: {}", author); + filter = Filter::Author(author.to_string()); + } + ["author-email", author_email] => { + log::trace!("author-email: {}", author_email); + filter = Filter::AuthorEmail(author_email.to_string()); + } + ["message", message] => { + log::trace!("message: {}", message); + filter = Filter::Message(message.to_string()); + } + _ => { log::debug!("invalid arg: {:?}", i); self.status = Status::Error(format!("Invalid search {:?}", i)); @@ -285,6 +297,18 @@ impl App { }; filter = Filter::DateRange(start.to_string(), end.to_string()); } + ["author", author] => { + log::trace!("author: {}", author); + filter = Filter::Author(author.to_string()); + } + ["author-email", author_email] => { + log::trace!("author-email: {}", author_email); + filter = Filter::AuthorEmail(author_email.to_string()); + } + ["message", message] => { + log::trace!("message: {}", message); + filter = Filter::Message(message.to_string()); + } ["line-range", pos] => { // get the start and end by splitting the pos by: .. let (start, end) = match pos.split_once("..") { From b75b240b00b95dd51c8c80010bb73855362d1778 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 24 Oct 2022 14:33:13 -0400 Subject: [PATCH 080/172] reograganized imports/clezned up --- cargo-function-history/src/app/actions.rs | 8 +++-- cargo-function-history/src/app/mod.rs | 14 +++----- cargo-function-history/src/app/ui.rs | 8 ++--- cargo-function-history/src/lib.rs | 3 +- git-function-history-gui/src/lib.rs | 8 ++--- git-function-history-lib/src/lib.rs | 39 +++++++++-------------- 6 files changed, 31 insertions(+), 49 deletions(-) diff --git a/cargo-function-history/src/app/actions.rs b/cargo-function-history/src/app/actions.rs index 8e4614b4..8cf8b2d4 100644 --- a/cargo-function-history/src/app/actions.rs +++ b/cargo-function-history/src/app/actions.rs @@ -1,6 +1,8 @@ -use std::collections::HashMap; -use std::fmt::{self, Display}; -use std::slice::Iter; +use std::{ + collections::HashMap, + fmt::{self, Display}, + slice::Iter, +}; use crate::keys::Key; diff --git a/cargo-function-history/src/app/mod.rs b/cargo-function-history/src/app/mod.rs index 8525a35c..7ce9cc55 100644 --- a/cargo-function-history/src/app/mod.rs +++ b/cargo-function-history/src/app/mod.rs @@ -1,16 +1,10 @@ -use self::actions::Actions; -use self::state::AppState; +use self::{actions::Actions, state::AppState}; use crate::{app::actions::Action, keys::Key}; use function_history_backend_thread::types::{ CommandResult, FilterType, FullCommand, ListType, Status, }; -use git_function_history::{ - languages::Language, - // BlockType, - FileFilterType, - Filter, -}; +use git_function_history::{languages::Language, FileFilterType, Filter}; use std::{ fs, io::{Read, Write}, @@ -248,7 +242,7 @@ impl App { filter = Filter::AuthorEmail(author_email.to_string()); } ["message", message] => { - log::trace!("message: {}", message); + log::trace!("message: {}", message); filter = Filter::Message(message.to_string()); } @@ -306,7 +300,7 @@ impl App { filter = Filter::AuthorEmail(author_email.to_string()); } ["message", message] => { - log::trace!("message: {}", message); + log::trace!("message: {}", message); filter = Filter::Message(message.to_string()); } ["line-range", pos] => { diff --git a/cargo-function-history/src/app/ui.rs b/cargo-function-history/src/app/ui.rs index 36462ad0..25e740ab 100644 --- a/cargo-function-history/src/app/ui.rs +++ b/cargo-function-history/src/app/ui.rs @@ -1,13 +1,13 @@ use std::collections::BTreeMap; use function_history_backend_thread::types::Status; -use tui::layout::{Alignment, Constraint, Direction, Layout, Rect}; -use tui::style::{Color, Style}; -use tui::widgets::{Block, Borders, Paragraph}; -use tui::Frame; use tui::{ backend::Backend, + layout::{Alignment, Constraint, Direction, Layout, Rect}, + style::{Color, Style}, text::{Span, Spans}, + widgets::{Block, Borders, Paragraph}, + Frame, }; use crate::app::App; diff --git a/cargo-function-history/src/lib.rs b/cargo-function-history/src/lib.rs index 2d119716..8056742f 100644 --- a/cargo-function-history/src/lib.rs +++ b/cargo-function-history/src/lib.rs @@ -1,7 +1,6 @@ use std::{cell::RefCell, io::stdout, path::PathBuf, process::exit, rc::Rc, time::Duration}; -use crate::app::ui; -use app::{state::AppState, App, AppReturn}; +use app::{state::AppState, ui, App, AppReturn}; use crossterm::event::{self, Event, KeyCode}; use eyre::Result; use keys::Key; diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index f11836b4..32584f34 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -2,12 +2,8 @@ use std::{sync::mpsc, time::Duration}; use eframe::{ self, - egui::{self, Button, Layout, Sense, SidePanel}, - epaint::Vec2, -}; -use eframe::{ - egui::{Label, TextEdit, TopBottomPanel, Visuals}, - epaint::Color32, + egui::{self, Button, Label, Layout, Sense, SidePanel, TextEdit, TopBottomPanel, Visuals}, + epaint::{Color32, Vec2}, }; use function_history_backend_thread::types::{ Command, CommandResult, FilterType, FullCommand, HistoryFilterType, ListType, Status, diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index ba8efbd2..8d223592 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -11,28 +11,28 @@ clippy::float_cmp, clippy::similar_names, clippy::missing_errors_doc, - clippy::return_self_not_must_use + clippy::return_self_not_must_use, + clippy::module_name_repetitions )] pub mod languages; /// Different types that can extracted from the result of `get_function_history`. pub mod types; -use languages::{rust, LanguageFilter, RubyFile}; - -use languages::{PythonFile, RustFile}; +use languages::{rust, LanguageFilter, PythonFile, RubyFile, RustFile}; #[cfg(feature = "parallel")] use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; -pub use types::FileType; + +use std::{error::Error, process::Command}; #[cfg(feature = "c_lang")] use languages::CFile; #[cfg(feature = "unstable")] use languages::GoFile; -use std::{error::Error, process::Command}; -pub use types::{Commit, FunctionHistory}; - -pub use crate::languages::Language; +pub use { + languages::Language, + types::{Commit, FileType, FunctionHistory}, +}; /// Different filetypes that can be used to ease the process of finding functions using `get_function_history`. #[derive(Debug, Clone, PartialEq, Eq)] @@ -185,7 +185,6 @@ pub fn get_function_history( Ok((id?, date?, author?, email?, message?)) }) .collect::, Box>>()?; - let mut file_history = FunctionHistory::new(String::from(name), Vec::new()); let err = "no history found".to_string(); // check if file is a rust file @@ -586,7 +585,7 @@ mod tests { fn not_found() { let output = get_function_history( "Not_a_function", - &FileFilterType::Absolute("src/test_functions.rs".to_string()), + &FileFilterType::None, &Filter::None, &languages::Language::Rust, ); @@ -700,9 +699,7 @@ mod tests { let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); match &output { - Ok(functions) => { - println!("{}", functions); - } + Ok(functions) => println!("{}", functions), Err(e) => println!("{}", e), } assert!(output.is_ok()); @@ -736,9 +733,7 @@ mod tests { let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); match &output { - Ok(functions) => { - println!("{}", functions); - } + Ok(functions) => println!("{}", functions), Err(e) => println!("{}", e), } assert!(output.is_ok()); @@ -762,9 +757,7 @@ mod tests { after = Utc::now() - now; println!("time taken to filter {}", after.num_seconds()); match &new_output { - Ok(res) => { - println!("{}", res) - } + Ok(res) => println!("{}", res), Err(e) => println!("{e}"), } let new_output = output.filter_by(&Filter::PLFilter(LanguageFilter::Rust( @@ -773,11 +766,9 @@ mod tests { after = Utc::now() - now; println!("time taken to filter {}", after.num_seconds()); match &new_output { - Ok(res) => { - println!("{}", res) - } + Ok(res) => println!("{}", res), Err(e) => println!("{e}"), } - assert!(new_output.is_ok()) + assert!(new_output.is_ok()); } } From e1305ce42cf026178219965de019cc683232445e Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 24 Oct 2022 14:42:33 -0400 Subject: [PATCH 081/172] added doc comment filters for rust --- git-function-history-lib/src/languages/rust.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 52b78ca1..9390f6c8 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -474,6 +474,8 @@ pub enum RustFilter { FunctionWithGeneric(String), /// when you want to filter by a function that has a specific attribute FunctionWithAttribute(String), + /// when you want to filter by a function that has or contains a specific doc comment + FunctionWithDocComment(String), } impl RustFilter { @@ -496,6 +498,11 @@ impl RustFilter { Self::FunctionWithLifetime(lifetime) => function.lifetime.contains(lifetime), Self::FunctionWithGeneric(generic) => function.generics.contains(generic), Self::FunctionWithAttribute(attribute) => function.attributes.contains(attribute), + Self::FunctionWithDocComment(comment) => function.doc_comments.iter().filter( + |doc| { + comment.contains(*doc) + } + ).count() > 0 } } } From a4ea11d2a3194f06c286438e56931f95afa24032 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Tue, 25 Oct 2022 05:48:54 +0000 Subject: [PATCH 082/172] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b8a7efb..3040ed79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ All notable changes to this project will be documented in this file. - Saving search history to a file now - Shortend filter loc - Search/filters are fixed was not working b/c of using window(2) +- Added more filters ## [2.1.0] - 2022-09-28 From fff74d352363e34af7c9efc1ced2e9cc040394e7 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Tue, 25 Oct 2022 20:08:13 -0400 Subject: [PATCH 083/172] more java stuff --- .../src/languages/java.rs | 67 +++++++++++++++---- 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/git-function-history-lib/src/languages/java.rs b/git-function-history-lib/src/languages/java.rs index 86f434cd..14ec0f49 100644 --- a/git-function-history-lib/src/languages/java.rs +++ b/git-function-history-lib/src/languages/java.rs @@ -1,6 +1,6 @@ use std::fmt; -use javaparser::parse::tree::CompilationUnit; +use javaparser::parse::tree::{CompilationUnit, CompilationUnitItem}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct JavaFunction { @@ -8,7 +8,7 @@ pub struct JavaFunction { pub lines: (usize, usize), pub args: Vec, pub body: String, - pub class: JavaClass, + pub class: Vec, } impl JavaFunction { @@ -17,7 +17,7 @@ impl JavaFunction { lines: (usize, usize), args: Vec, body: String, - class: JavaClass, + class: Vec, ) -> Self { Self { name, @@ -31,19 +31,27 @@ impl JavaFunction { impl fmt::Display for JavaFunction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.class.top)?; + // TODO: sort top and bottom by line number + write!(f, "{}", self.class.iter().map(|c| format!("{}\n", c.top)).collect::>().join(""))?; write!(f, "{}", self.body)?; - write!(f, "{}", self.class.bottom)?; + write!(f, "{}", self.class.iter().rev().map(|c| format!("\n{}", c.bottom)).collect::>().join(""))?; Ok(()) } } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct JavaClass { +pub struct JavaBlock { pub name: String, pub line: (usize, usize), pub top: String, pub bottom: String, + pub type_: JavaBlockType, +} +#[derive(Debug, Clone, PartialEq, Eq, Copy)] +pub enum JavaBlockType { + Class, + Enum, + Interface, } pub(crate) fn find_function_in_file( @@ -53,21 +61,24 @@ pub(crate) fn find_function_in_file( let file = javaparser::parse::apply(file_contents, "").map_err(|_| "Parse error")?; let parsed = file.unit.clone().items; println!("{:#?}", parsed); + let mut functions = Vec::new(); + for unit in parsed { + extract_methods_from_compilation_unit(&unit, name).map(|f| functions.push(f))?; + } Err("Not implemented".to_string()) } fn extract_methods_from_compilation_unit( - unit: &CompilationUnit<'_>, + unit: &CompilationUnitItem<'_>, name: &str, ) -> Result, String> { let mut methods = Vec::new(); - for item in &unit.items { - match item { - javaparser::parse::tree::CompilationUnitItem::Class(_) => todo!(), - javaparser::parse::tree::CompilationUnitItem::Interface(_) => todo!(), - javaparser::parse::tree::CompilationUnitItem::Annotation(_) => todo!(), - javaparser::parse::tree::CompilationUnitItem::Enum(_) => todo!(), - } + + match unit { + javaparser::parse::tree::CompilationUnitItem::Class(_) => todo!(), + javaparser::parse::tree::CompilationUnitItem::Interface(_) => todo!(), + javaparser::parse::tree::CompilationUnitItem::Annotation(_) => todo!(), + javaparser::parse::tree::CompilationUnitItem::Enum(_) => todo!(), } Ok(methods) } @@ -87,4 +98,32 @@ mod java_test { "#; let function = find_function_in_file(file_contents, "main").unwrap(); } + + #[test] + fn java_fn_print() { + let java_class1 = JavaBlock { + name: "Test".to_string(), + line: (1, 1), + top: "public class Test {".to_string(), + bottom: "}".to_string(), + type_: JavaBlockType::Class, + }; + let java_class2 = JavaBlock { + name: "Test2".to_string(), + line: (1, 1), + top: " public class Test2 {".to_string(), + bottom: " }".to_string(), + type_: JavaBlockType::Class, + }; + let java_fn = JavaFunction::new( + "main".to_string(), + (1, 1), + vec![], + " public static void main(String[] args) { + System.out.println(\"Hello, World\"); + }".to_string(), + vec![java_class1, java_class2], + ); + println!("{}", java_fn); + } } From ed6fafeb9956e2c8e9160aeebd28eb556a9332b3 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 26 Oct 2022 21:16:19 -0400 Subject: [PATCH 084/172] idk what im doing but we can now semi find methods in java --- .../src/languages/java.rs | 153 +++++++++++++++++- 1 file changed, 146 insertions(+), 7 deletions(-) diff --git a/git-function-history-lib/src/languages/java.rs b/git-function-history-lib/src/languages/java.rs index 14ec0f49..fb9998b3 100644 --- a/git-function-history-lib/src/languages/java.rs +++ b/git-function-history-lib/src/languages/java.rs @@ -60,25 +60,162 @@ pub(crate) fn find_function_in_file( ) -> Result, String> { let file = javaparser::parse::apply(file_contents, "").map_err(|_| "Parse error")?; let parsed = file.unit.clone().items; - println!("{:#?}", parsed); + // println!("{:#?}", parsed); let mut functions = Vec::new(); for unit in parsed { - extract_methods_from_compilation_unit(&unit, name).map(|f| functions.push(f))?; + extract_methods_from_compilation_unit(&unit, name).map(|f| functions.extend(f))?; } - Err("Not implemented".to_string()) + Ok(functions) } fn extract_methods_from_compilation_unit( unit: &CompilationUnitItem<'_>, name: &str, ) -> Result, String> { + // recursively search for items with type Method + let mut methods = Vec::new(); match unit { - javaparser::parse::tree::CompilationUnitItem::Class(_) => todo!(), - javaparser::parse::tree::CompilationUnitItem::Interface(_) => todo!(), - javaparser::parse::tree::CompilationUnitItem::Annotation(_) => todo!(), - javaparser::parse::tree::CompilationUnitItem::Enum(_) => todo!(), + javaparser::parse::tree::CompilationUnitItem::Class(class) => { + let mut class_methods = Vec::new(); + for item in &class.body.items { + extract_methods_from_class_item(item, name).map(|f| class_methods.extend(f))?; + } + methods.extend(class_methods); + + } + javaparser::parse::tree::CompilationUnitItem::Interface(interface) => { + let mut interface_methods = Vec::new(); + for item in &interface.body.items { + extract_methods_from_class_item(item, name).map(|f| interface_methods.extend(f))?; + } + methods.extend(interface_methods); + }, + javaparser::parse::tree::CompilationUnitItem::Enum(enum_) => { + let mut enum_methods = Vec::new(); + if let Some(enum_body) = &enum_.body_opt { + for item in &enum_body.items { + extract_methods_from_class_item(item, name).map(|f| enum_methods.extend(f))?; + } + } + methods.extend(enum_methods); + }, + javaparser::parse::tree::CompilationUnitItem::Annotation(annotation) => { + let mut annotation_methods = Vec::new(); + for item in &annotation.body.items { + extract_methods_from_annotation_item(item, name).map(|f| annotation_methods.extend(f))?; + } + methods.extend(annotation_methods); + + }, + } + Ok(methods) +} + +fn extract_methods_from_class_item( + item: &javaparser::parse::tree::ClassBodyItem<'_>, + name: &str, +) -> Result, String> { + let mut methods = Vec::new(); + match item { + javaparser::parse::tree::ClassBodyItem::Method(method) => { + // println!("{:#?}", method); + if method.name.fragment == name { + let args = vec![]; + // method + // .parameters + // .iter() + // .map(|p| p.name.to_string()) + // .collect::>(); + // let body = method.body.to_string(); + // let lines = (method.line, method.line + body.lines().count()); + let class = Vec::new(); + methods.push(JavaFunction::new( + "test".to_string(), + (0, 0), + args, + "test".to_string(), + class, + )); + } + } + javaparser::parse::tree::ClassBodyItem::Class(class) => { + let mut class_methods = Vec::new(); + for item in &class.body.items { + extract_methods_from_class_item(item, name).map(|f| class_methods.extend(f))?; + } + methods.extend(class_methods); + } + javaparser::parse::tree::ClassBodyItem::Interface(interface) => { + let mut interface_methods = Vec::new(); + for item in &interface.body.items { + extract_methods_from_class_item(item, name).map(|f| interface_methods.extend(f))?; + } + methods.extend(interface_methods); + } + javaparser::parse::tree::ClassBodyItem::Enum(enum_) => { + let mut enum_methods = Vec::new(); + if let Some(enum_body) = &enum_.body_opt { + for item in &enum_body.items { + extract_methods_from_class_item(item, name).map(|f| enum_methods.extend(f))?; + } + } + methods.extend(enum_methods); + } + javaparser::parse::tree::ClassBodyItem::Annotation(annotation) => { + let mut annotation_methods = Vec::new(); + for item in &annotation.body.items { + extract_methods_from_annotation_item(item, name).map(|f| annotation_methods.extend(f))?; + } + methods.extend(annotation_methods); + } + javaparser::parse::tree::ClassBodyItem::Constructor(constructor) => {} + javaparser::parse::tree::ClassBodyItem::FieldDeclarators(field_declarators) => {} + javaparser::parse::tree::ClassBodyItem::StaticInitializer(static_initializer) => {} + + } + Ok(methods) +} + +fn extract_methods_from_annotation_item( + item: &javaparser::parse::tree::AnnotationBodyItem<'_>, + name: &str, +) -> Result, String> { + let mut methods = Vec::new(); + match item { + javaparser::parse::tree::AnnotationBodyItem::Annotation(annotation) => { + let mut annotation_methods = Vec::new(); + for item in &annotation.body.items { + extract_methods_from_annotation_item(item, name).map(|f| annotation_methods.extend(f))?; + } + methods.extend(annotation_methods); + } + javaparser::parse::tree::AnnotationBodyItem::FieldDeclarators(field_declarators) => {} + javaparser::parse::tree::AnnotationBodyItem::Class(class) => { + let mut class_methods = Vec::new(); + for item in &class.body.items { + extract_methods_from_class_item(item, name).map(|f| class_methods.extend(f))?; + } + methods.extend(class_methods); + } + javaparser::parse::tree::AnnotationBodyItem::Interface(interface) => { + let mut interface_methods = Vec::new(); + for item in &interface.body.items { + extract_methods_from_class_item(item, name).map(|f| interface_methods.extend(f))?; + } + methods.extend(interface_methods); + } + javaparser::parse::tree::AnnotationBodyItem::Enum(enum_) => { + let mut enum_methods = Vec::new(); + if let Some(enum_body) = &enum_.body_opt { + for item in &enum_body.items { + extract_methods_from_class_item(item, name).map(|f| enum_methods.extend(f))?; + } + } + methods.extend(enum_methods); + } + javaparser::parse::tree::AnnotationBodyItem::Param(param) => {} } Ok(methods) } @@ -90,6 +227,7 @@ mod java_test { #[test] fn java() { let file_contents = r#" + @Company public class Test { public static void main(String[] args) { System.out.println("Hello, World"); @@ -97,6 +235,7 @@ mod java_test { } "#; let function = find_function_in_file(file_contents, "main").unwrap(); + println!("{:#?}", function); } #[test] From da1fbfd67113449031fec16ade806c64f758291b Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 27 Oct 2022 00:35:00 -0400 Subject: [PATCH 085/172] fix bug where if python function was last piece of code it wouldn't be included --- git-function-history-lib/README.md | 6 ++- .../src/languages/java.rs | 50 ++++++++++++------- git-function-history-lib/src/languages/mod.rs | 4 +- .../src/languages/python.rs | 49 ++++++++++++++---- .../src/languages/rust.rs | 13 +++-- .../src/test_functions.py | 6 ++- 6 files changed, 94 insertions(+), 34 deletions(-) diff --git a/git-function-history-lib/README.md b/git-function-history-lib/README.md index 6481f3e7..8105ff7f 100644 --- a/git-function-history-lib/README.md +++ b/git-function-history-lib/README.md @@ -12,4 +12,8 @@ Use the latest [crates.io](https://crates.io/crates/git_function_history) by put - parallel: use rayon to parallelize the git log search - --no-default-features: disable parallelism - c-lang: adds support c (requires you to have a c compiler installed) (see the [c-lib]() docs for more information) -- unstable: enable some parsers that require nightly rust so run `cargo +nightly` to use them \ No newline at end of file +- unstable: enable some parsers that require nightly rust so run `cargo +nightly` to use them + +## known issues + +- python: since the parser only finds the beginning of the function we have to use some workarounds to find the end of the function. This means that if you have a function that anything from the end of one function to either the beginning of another function or the end of the file that is not python code for example a comment it will be included in the function. diff --git a/git-function-history-lib/src/languages/java.rs b/git-function-history-lib/src/languages/java.rs index fb9998b3..b69685bc 100644 --- a/git-function-history-lib/src/languages/java.rs +++ b/git-function-history-lib/src/languages/java.rs @@ -32,9 +32,24 @@ impl JavaFunction { impl fmt::Display for JavaFunction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // TODO: sort top and bottom by line number - write!(f, "{}", self.class.iter().map(|c| format!("{}\n", c.top)).collect::>().join(""))?; + write!( + f, + "{}", + self.class + .iter() + .map(|c| format!("{}\n", c.top)) + .collect::() + )?; write!(f, "{}", self.body)?; - write!(f, "{}", self.class.iter().rev().map(|c| format!("\n{}", c.bottom)).collect::>().join(""))?; + write!( + f, + "{}", + self.class + .iter() + .rev() + .map(|c| format!("\n{}", c.bottom)) + .collect::() + )?; Ok(()) } } @@ -76,14 +91,13 @@ fn extract_methods_from_compilation_unit( let mut methods = Vec::new(); - match unit { + match unit { javaparser::parse::tree::CompilationUnitItem::Class(class) => { let mut class_methods = Vec::new(); for item in &class.body.items { extract_methods_from_class_item(item, name).map(|f| class_methods.extend(f))?; } methods.extend(class_methods); - } javaparser::parse::tree::CompilationUnitItem::Interface(interface) => { let mut interface_methods = Vec::new(); @@ -91,7 +105,7 @@ fn extract_methods_from_compilation_unit( extract_methods_from_class_item(item, name).map(|f| interface_methods.extend(f))?; } methods.extend(interface_methods); - }, + } javaparser::parse::tree::CompilationUnitItem::Enum(enum_) => { let mut enum_methods = Vec::new(); if let Some(enum_body) = &enum_.body_opt { @@ -100,15 +114,15 @@ fn extract_methods_from_compilation_unit( } } methods.extend(enum_methods); - }, + } javaparser::parse::tree::CompilationUnitItem::Annotation(annotation) => { let mut annotation_methods = Vec::new(); for item in &annotation.body.items { - extract_methods_from_annotation_item(item, name).map(|f| annotation_methods.extend(f))?; + extract_methods_from_annotation_item(item, name) + .map(|f| annotation_methods.extend(f))?; } methods.extend(annotation_methods); - - }, + } } Ok(methods) } @@ -124,10 +138,10 @@ fn extract_methods_from_class_item( if method.name.fragment == name { let args = vec![]; // method - // .parameters - // .iter() - // .map(|p| p.name.to_string()) - // .collect::>(); + // .parameters + // .iter() + // .map(|p| p.name.to_string()) + // .collect::>(); // let body = method.body.to_string(); // let lines = (method.line, method.line + body.lines().count()); let class = Vec::new(); @@ -166,14 +180,14 @@ fn extract_methods_from_class_item( javaparser::parse::tree::ClassBodyItem::Annotation(annotation) => { let mut annotation_methods = Vec::new(); for item in &annotation.body.items { - extract_methods_from_annotation_item(item, name).map(|f| annotation_methods.extend(f))?; + extract_methods_from_annotation_item(item, name) + .map(|f| annotation_methods.extend(f))?; } methods.extend(annotation_methods); } javaparser::parse::tree::ClassBodyItem::Constructor(constructor) => {} javaparser::parse::tree::ClassBodyItem::FieldDeclarators(field_declarators) => {} javaparser::parse::tree::ClassBodyItem::StaticInitializer(static_initializer) => {} - } Ok(methods) } @@ -187,7 +201,8 @@ fn extract_methods_from_annotation_item( javaparser::parse::tree::AnnotationBodyItem::Annotation(annotation) => { let mut annotation_methods = Vec::new(); for item in &annotation.body.items { - extract_methods_from_annotation_item(item, name).map(|f| annotation_methods.extend(f))?; + extract_methods_from_annotation_item(item, name) + .map(|f| annotation_methods.extend(f))?; } methods.extend(annotation_methods); } @@ -260,7 +275,8 @@ mod java_test { vec![], " public static void main(String[] args) { System.out.println(\"Hello, World\"); - }".to_string(), + }" + .to_string(), vec![java_class1, java_class2], ); println!("{}", java_fn); diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index b9a578bc..a24569f2 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -280,7 +280,9 @@ macro_rules! make_file_time_test { println!("{}", i); } } - Err(_) => {} + Err(e) => { + println!("{}", e); + } } println!("{} took {:?}", stringify!($name), end - start); assert!(ok.is_ok()); diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index caa48c7b..b9c01d0c 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -1,12 +1,12 @@ -use std::{collections::HashMap, fmt}; - use rustpython_parser::{ ast::{Located, StatementType}, location::Location, parser, }; +use std::collections::VecDeque; +use std::{collections::HashMap, fmt}; -use crate::impl_function_trait; +use crate::{impl_function_trait, UnwrapToError}; use super::FunctionTrait; @@ -75,8 +75,20 @@ pub(crate) fn find_function_in_file( let ast = parser::parse_program(file_contents)?; let mut functions = vec![]; let mut last = None; - for stmt in ast.statements { - get_functions(stmt, &mut functions, name, &mut last, &mut None); + + if ast.statements.is_empty() { + return Err("No code found")?; + } + let mut new_ast = VecDeque::from(ast.statements); + loop { + if new_ast.is_empty() { + break; + } + let stmt = new_ast + .pop_front() + .unwrap_to_error("could not get statement")?; + let next = new_ast.front(); + get_functions(stmt, next, &mut functions, name, &mut last, &mut None); } let mut starts = file_contents .match_indices('\n') @@ -89,7 +101,15 @@ pub(crate) fn find_function_in_file( .enumerate() .collect::>(); let mut new = Vec::new(); - for func in functions { + for mut func in functions { + if func.1 .0 == func.1 .1 { + // get the last line of the file + let last_line = file_contents.lines().last().unwrap_to_error("could not get last line")?; + let row = file_contents.lines().count(); + let column = last_line.len(); + let end = Location::new(row, column); + func.1 .1 = end; + } // get the function body based on the location let start = func.1 .0.row(); let end = func.1 .1.row(); @@ -145,9 +165,16 @@ fn fun_name1( last_found_fn: &mut Option<(StatementType, Location)>, other_last_found_fn: &mut Option<(StatementType, Location)>, ) { - for stmt in body { + let mut new_ast = VecDeque::from(body); + loop { + if new_ast.is_empty() { + break; + } + let stmt = new_ast.pop_front().expect("could not get statement"); + let next = new_ast.front(); get_functions( stmt, + next, functions, lookup_name, last_found_fn, @@ -172,6 +199,7 @@ fn fun_name( fn get_functions<'a>( stmt: Located, + next_stmt: Option<&Located>, functions: &mut Vec<(StatementType, (Location, Location))>, lookup_name: &str, last_found_fn: &'a mut Option<(StatementType, Location)>, @@ -184,8 +212,11 @@ fn get_functions<'a>( std::mem::swap(last, &mut new); functions.push((new.0, (new.1, stmt.location))); } else { - // TODO: figure out if its the last node if so then we can push it here otherwise we need to wait for the next node - *last_found_fn = Some((stmt.node, stmt.location)); + if next_stmt.is_none() { + functions.push((stmt.node, (stmt.location, stmt.location))); + } else { + *last_found_fn = Some((stmt.node, stmt.location)); + } } } diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 9390f6c8..4aaa00e2 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -498,11 +498,14 @@ impl RustFilter { Self::FunctionWithLifetime(lifetime) => function.lifetime.contains(lifetime), Self::FunctionWithGeneric(generic) => function.generics.contains(generic), Self::FunctionWithAttribute(attribute) => function.attributes.contains(attribute), - Self::FunctionWithDocComment(comment) => function.doc_comments.iter().filter( - |doc| { - comment.contains(*doc) - } - ).count() > 0 + Self::FunctionWithDocComment(comment) => { + function + .doc_comments + .iter() + .filter(|doc| comment.contains(*doc)) + .count() + > 0 + } } } } diff --git a/git-function-history-lib/src/test_functions.py b/git-function-history-lib/src/test_functions.py index c29ed9f1..92023c4a 100644 --- a/git-function-history-lib/src/test_functions.py +++ b/git-function-history-lib/src/test_functions.py @@ -9,4 +9,8 @@ def empty_test(): def test_with_assert(): assert True -passing_test = test_with_assert \ No newline at end of file +passing_test = test_with_assert + +def empty_test(): + """This is an empty test with a docstring""" + pass From 368533b4ea2c0935f608c10bac7b62a6307e6d85 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 27 Oct 2022 14:42:43 -0400 Subject: [PATCH 086/172] more java ideas --- .../src/languages/java.rs | 25 ++++++++++++------- .../src/languages/python.rs | 13 +++++----- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/git-function-history-lib/src/languages/java.rs b/git-function-history-lib/src/languages/java.rs index b69685bc..0576cbff 100644 --- a/git-function-history-lib/src/languages/java.rs +++ b/git-function-history-lib/src/languages/java.rs @@ -1,6 +1,6 @@ use std::fmt; -use javaparser::parse::tree::{CompilationUnit, CompilationUnitItem}; +use javaparser::{analyze::definition::MethodDef, parse::tree::CompilationUnitItem}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct JavaFunction { @@ -75,7 +75,6 @@ pub(crate) fn find_function_in_file( ) -> Result, String> { let file = javaparser::parse::apply(file_contents, "").map_err(|_| "Parse error")?; let parsed = file.unit.clone().items; - // println!("{:#?}", parsed); let mut functions = Vec::new(); for unit in parsed { extract_methods_from_compilation_unit(&unit, name).map(|f| functions.extend(f))?; @@ -88,7 +87,6 @@ fn extract_methods_from_compilation_unit( name: &str, ) -> Result, String> { // recursively search for items with type Method - let mut methods = Vec::new(); match unit { @@ -136,6 +134,10 @@ fn extract_methods_from_class_item( javaparser::parse::tree::ClassBodyItem::Method(method) => { // println!("{:#?}", method); if method.name.fragment == name { + let methdef = javaparser::analyze::build::method::build(method); + // let def = javaparser::extract::Definition::Method(methdef); + println!("{:#?}", methdef.span_opt.map(|s| s.fragment)); + // println!("{:#?}", methdef); let args = vec![]; // method // .parameters @@ -144,6 +146,10 @@ fn extract_methods_from_class_item( // .collect::>(); // let body = method.body.to_string(); // let lines = (method.line, method.line + body.lines().count()); + // println!("{:#?}", method); + + // to find the the bottom of the class see if block_opt is some then find the span of the last block find the first } after that and then find the line number of that + // to find the top of the class find the first { before the method and then find the line number of that first check modifiers if not use return type let class = Vec::new(); methods.push(JavaFunction::new( "test".to_string(), @@ -185,9 +191,9 @@ fn extract_methods_from_class_item( } methods.extend(annotation_methods); } - javaparser::parse::tree::ClassBodyItem::Constructor(constructor) => {} - javaparser::parse::tree::ClassBodyItem::FieldDeclarators(field_declarators) => {} - javaparser::parse::tree::ClassBodyItem::StaticInitializer(static_initializer) => {} + javaparser::parse::tree::ClassBodyItem::Constructor(_) + | javaparser::parse::tree::ClassBodyItem::FieldDeclarators(_) + | javaparser::parse::tree::ClassBodyItem::StaticInitializer(_) => {} } Ok(methods) } @@ -206,7 +212,7 @@ fn extract_methods_from_annotation_item( } methods.extend(annotation_methods); } - javaparser::parse::tree::AnnotationBodyItem::FieldDeclarators(field_declarators) => {} + javaparser::parse::tree::AnnotationBodyItem::Class(class) => { let mut class_methods = Vec::new(); for item in &class.body.items { @@ -230,7 +236,8 @@ fn extract_methods_from_annotation_item( } methods.extend(enum_methods); } - javaparser::parse::tree::AnnotationBodyItem::Param(param) => {} + javaparser::parse::tree::AnnotationBodyItem::Param(_) + | javaparser::parse::tree::AnnotationBodyItem::FieldDeclarators(_) => {} } Ok(methods) } @@ -244,7 +251,7 @@ mod java_test { let file_contents = r#" @Company public class Test { - public static void main(String[] args) { + void main(String[] args) { System.out.println("Hello, World"); } } diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index b9c01d0c..ccc6ad3a 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -104,7 +104,10 @@ pub(crate) fn find_function_in_file( for mut func in functions { if func.1 .0 == func.1 .1 { // get the last line of the file - let last_line = file_contents.lines().last().unwrap_to_error("could not get last line")?; + let last_line = file_contents + .lines() + .last() + .unwrap_to_error("could not get last line")?; let row = file_contents.lines().count(); let column = last_line.len(); let end = Location::new(row, column); @@ -211,12 +214,10 @@ fn get_functions<'a>( let mut new = (stmt.node, stmt.location); std::mem::swap(last, &mut new); functions.push((new.0, (new.1, stmt.location))); + } else if next_stmt.is_none() { + functions.push((stmt.node, (stmt.location, stmt.location))); } else { - if next_stmt.is_none() { - functions.push((stmt.node, (stmt.location, stmt.location))); - } else { - *last_found_fn = Some((stmt.node, stmt.location)); - } + *last_found_fn = Some((stmt.node, stmt.location)); } } From 866983d823087506b6b7760ddf3f22ba4223cb0c Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 27 Oct 2022 15:18:52 -0400 Subject: [PATCH 087/172] working on a filter macro [broken] --- git-function-history-lib/src/languages/go.rs | 5 -- .../src/languages/java.rs | 18 +++--- .../src/languages/ruby.rs | 13 +++-- git-function-history-lib/src/types.rs | 56 ++++++++++++++++++- 4 files changed, 71 insertions(+), 21 deletions(-) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index 4971a824..3818902d 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -152,7 +152,6 @@ pub(crate) fn find_function_in_file( pub enum GoFilter { FunctionWithParameter(String), FunctionWithReturnType(String), - FunctionInLines(usize, usize), } impl GoFilter { @@ -162,10 +161,6 @@ impl GoFilter { Self::FunctionWithReturnType(ret) => { func.returns.as_ref().map_or(false, |x| x.contains(ret)) } - Self::FunctionInLines(start, end) => { - let (s, e) = func.get_total_lines(); - s >= *start && e <= *end - } } } } diff --git a/git-function-history-lib/src/languages/java.rs b/git-function-history-lib/src/languages/java.rs index 0576cbff..9e023a11 100644 --- a/git-function-history-lib/src/languages/java.rs +++ b/git-function-history-lib/src/languages/java.rs @@ -37,7 +37,7 @@ impl fmt::Display for JavaFunction { "{}", self.class .iter() - .map(|c| format!("{}\n", c.top)) + .map(|c| format!("{}\n...\n", c.top)) .collect::() )?; write!(f, "{}", self.body)?; @@ -47,7 +47,7 @@ impl fmt::Display for JavaFunction { self.class .iter() .rev() - .map(|c| format!("\n{}", c.bottom)) + .map(|c| format!("\n...\n{}", c.bottom)) .collect::() )?; Ok(()) @@ -265,24 +265,24 @@ mod java_test { let java_class1 = JavaBlock { name: "Test".to_string(), line: (1, 1), - top: "public class Test {".to_string(), - bottom: "}".to_string(), + top: "1: public class Test {".to_string(), + bottom: "30: }".to_string(), type_: JavaBlockType::Class, }; let java_class2 = JavaBlock { name: "Test2".to_string(), line: (1, 1), - top: " public class Test2 {".to_string(), - bottom: " }".to_string(), + top: "3: public class Test2 {".to_string(), + bottom: "28: }".to_string(), type_: JavaBlockType::Class, }; let java_fn = JavaFunction::new( "main".to_string(), (1, 1), vec![], - " public static void main(String[] args) { - System.out.println(\"Hello, World\"); - }" + "5: public static void main(String[] args) { +7: System.out.println(\"Hello, World\"); +8: }" .to_string(), vec![java_class1, java_class2], ); diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 5a143e8a..ef82d54b 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -261,15 +261,18 @@ impl FunctionTrait for RubyFunction { } #[derive(Debug, Clone, PartialEq, Eq)] pub enum RubyFilter { - FunctionInLines((usize, usize)), + FunctionInClass(String), + FunctionWithParameter(String), } impl RubyFilter { - pub const fn matches(&self, function: &RubyFunction) -> bool { + pub fn matches(&self, function: &RubyFunction) -> bool { match self { - Self::FunctionInLines((start, end)) => { - function.lines.0 >= *start && function.lines.1 <= *end - } + Self::FunctionInClass(name) => match &function.class { + Some(class) => *name == class.name, + None => false, + }, + Self::FunctionWithParameter(name) => function.args.contains(name), } } } diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 29fc43f2..89c339b9 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -9,8 +9,8 @@ use std::{ }; use crate::{ - languages::{FileTrait, FunctionTrait, PythonFile, RubyFile, RustFile}, - Filter, + languages::{FileTrait, FunctionTrait, PythonFile, RubyFile, RustFile, rust::RustFilter}, + Filter, get_function_history, }; #[cfg(feature = "c_lang")] @@ -494,6 +494,58 @@ impl FunctionHistory { } } +macro_rules! filter_by { +// option 1: takes a filter +($self:ident, $filter:ident) => { + // #[cfg(feature = "parallel")] + // let t = $self.commit_history.par_iter(); + // #[cfg(not(feature = "parallel"))] + // let t = $self.commit_history.iter(); + // let vec: Vec = t + // .filter(|f| f.filter_by(&$filter).is_ok()) + // .cloned() + // .collect(); + + // if vec.is_empty() { + // return Err("No history found for the filter")?; + // } + // Ok(Self { + // commit_history: vec, + // name: $self.name.clone(), + // current_pos: 0, + // current_iter_pos: 0, + // }) + $self.filter_by(&$filter) +}; +// option 2: takes a PLFilter variant +($self:ident, $pl_filter:ident) => { + + $self.filter_by(&$pl_filter) + +}; + +// option 3: takes a language specific filter ie RustFilter and a language ie Rust +($self:ident, $rust_filter:expr, $language:ident) => { + $self.filter_by(&Filter::PLFilter(PLFilter::$language($rust_filter))) +}; + + + + + +} + +#[test] +fn test_filter_by() { + let repo = get_function_history!( + name = "empty_test" + ).expect("Failed to get function history"); + let filter = Filter::CommitHash("c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0".to_string()); + filter_by!(repo, RustFilter::FunctionInBlock(crate::languages::rust::BlockType::Impl), RustFilter) + // assert_eq!(filtered_repo.commit_history.len(), 1); + // assert_eq!(filtered_repo.commit_history[0].commit_hash, "c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0"); +} + impl Display for FunctionHistory { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { writeln!(f, "{}", self.commit_history[self.current_pos])?; From e75d3bbf646ddbc682a995284fcd4a03a92724dd Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Fri, 28 Oct 2022 10:13:59 -0400 Subject: [PATCH 088/172] lib: fixed bug where I didnt understand how cfg-if works, also filter_by macro works just neeeds docs --- .../src/languages/java.rs | 2 +- git-function-history-lib/src/lib.rs | 52 +++++++- git-function-history-lib/src/types.rs | 113 +++--------------- 3 files changed, 66 insertions(+), 101 deletions(-) diff --git a/git-function-history-lib/src/languages/java.rs b/git-function-history-lib/src/languages/java.rs index 9e023a11..d3212a75 100644 --- a/git-function-history-lib/src/languages/java.rs +++ b/git-function-history-lib/src/languages/java.rs @@ -283,7 +283,7 @@ mod java_test { "5: public static void main(String[] args) { 7: System.out.println(\"Hello, World\"); 8: }" - .to_string(), + .to_string(), vec![java_class1, java_class2], ); println!("{}", java_fn); diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 8d223592..12b6eb91 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -418,25 +418,32 @@ fn find_function_in_commit_with_filetype( Language::All => { cfg_if::cfg_if! { if #[cfg(feature = "c_lang")] { - if file.ends_with(".c") || file.ends_with(".h") { + if file.ends_with(".c") || file.ends_with(".h") || file.ends_with(".rs") || file.ends_with(".py") || file.ends_with(".rb") { files.push(file); } } else if #[cfg(feature = "unstable")] { - if file.ends_with(".go") { + if file.ends_with(".go") || file.ends_with(".rs") || file.ends_with(".py") || file.ends_with(".rb"){ + files.push(file); + } + } + else if #[cfg(all(feature = "unstable", feature = "c_lang"))] { + if file.ends_with(".c") || file.ends_with(".h") || file.ends_with(".go") || file.ends_with(".rs") || file.ends_with(".py") || file.ends_with(".rb") { files.push(file); } } else { - if file.ends_with(".py") || file.ends_with(".rs") || file.ends_with(".rb") { + if file.ends_with(".rs") || file.ends_with(".py") || file.ends_with(".rb") { files.push(file); } } + } } }, } } + let err = "no function found".to_string(); #[cfg(feature = "parellel")] let t = files.par_iter(); @@ -545,7 +552,10 @@ impl UnwrapToError for Option { mod tests { use chrono::Utc; - use crate::languages::{rust::BlockType, FileTrait}; + use crate::languages::{ + rust::{BlockType, RustFilter}, + FileTrait, + }; use super::*; #[test] @@ -771,4 +781,38 @@ mod tests { } assert!(new_output.is_ok()); } + + #[test] + fn test_filter_by() { + let repo = + get_function_history!(name = "empty_test").expect("Failed to get function history"); + let f1 = filter_by!( + repo, + RustFilter::FunctionInBlock(crate::languages::rust::BlockType::Impl), + Rust + ); + match f1 { + Ok(_) => println!("filter 1 ok"), + Err(e) => println!("error: {}", e), + } + let f2 = filter_by!( + repo, + Filter::CommitHash("c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0".to_string()) + ); + match f2 { + Ok(_) => println!("filter 2 ok"), + Err(e) => println!("error: {}", e), + } + let f3 = filter_by!( + repo, + LanguageFilter::Rust(RustFilter::FunctionInBlock( + crate::languages::rust::BlockType::Impl + )), + 1 + ); + match f3 { + Ok(_) => println!("filter 3 ok"), + Err(e) => println!("error: {}", e), + } + } } diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 89c339b9..ee2193c2 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -9,8 +9,8 @@ use std::{ }; use crate::{ - languages::{FileTrait, FunctionTrait, PythonFile, RubyFile, RustFile, rust::RustFilter}, - Filter, get_function_history, + languages::{FileTrait, FunctionTrait, PythonFile, RubyFile, RustFile}, + Filter, }; #[cfg(feature = "c_lang")] @@ -371,50 +371,6 @@ impl FunctionHistory { /// /// history.filter_by(&Filter::Directory("app".to_string())).unwrap(); /// ``` - // pub fn filter_by(&self, filter: &Filter) -> Result> { - // #[cfg(feature = "parallel")] - // let t = self.commit_history.par_iter(); - // #[cfg(not(feature = "parallel"))] - // let t = self.commit_history.iter(); - // let vec: Vec = t - // .filter(|f| match filter { - // Filter::FunctionInLines(..) - // | Filter::Directory(_) - // | Filter::FileAbsolute(_) - // | Filter::PLFilter(_) - // | Filter::FileRelative(_) => f.filter_by(filter).is_ok(), - // Filter::CommitHash(commit_hash) => &f.commit_hash == commit_hash, - // Filter::Date(date) => &f.date.to_rfc2822() == date, - // Filter::DateRange(start, end) => { - // let start = match DateTime::parse_from_rfc2822(start) { - // Ok(date) => date, - // Err(_) => return false, - // }; - // let end = match DateTime::parse_from_rfc2822(end) { - // Ok(date) => date, - // Err(_) => return false, - // }; - // f.date >= start || f.date <= end - // } - // Filter::Author(author) => &f.author == author, - // Filter::AuthorEmail(email) => &f.email == email, - // Filter::Message(message) => f.message.contains(message), - // Filter::None => true, - // }) - // .cloned() - // .collect(); - - // if vec.is_empty() { - // return Err("No history found for the filter")?; - // } - // Ok(Self { - // commit_history: vec, - // name: self.name.clone(), - // current_pos: 0, - // current_iter_pos: 0, - // }) - // } - pub fn filter_by(&self, filter: &Filter) -> Result> { #[cfg(feature = "parallel")] let t = self.commit_history.par_iter(); @@ -493,57 +449,22 @@ impl FunctionHistory { }) } } - +// TODO: add docs +#[macro_export] macro_rules! filter_by { -// option 1: takes a filter -($self:ident, $filter:ident) => { - // #[cfg(feature = "parallel")] - // let t = $self.commit_history.par_iter(); - // #[cfg(not(feature = "parallel"))] - // let t = $self.commit_history.iter(); - // let vec: Vec = t - // .filter(|f| f.filter_by(&$filter).is_ok()) - // .cloned() - // .collect(); - - // if vec.is_empty() { - // return Err("No history found for the filter")?; - // } - // Ok(Self { - // commit_history: vec, - // name: $self.name.clone(), - // current_pos: 0, - // current_iter_pos: 0, - // }) - $self.filter_by(&$filter) -}; -// option 2: takes a PLFilter variant -($self:ident, $pl_filter:ident) => { - - $self.filter_by(&$pl_filter) - -}; - -// option 3: takes a language specific filter ie RustFilter and a language ie Rust -($self:ident, $rust_filter:expr, $language:ident) => { - $self.filter_by(&Filter::PLFilter(PLFilter::$language($rust_filter))) -}; - - - - - -} - -#[test] -fn test_filter_by() { - let repo = get_function_history!( - name = "empty_test" - ).expect("Failed to get function history"); - let filter = Filter::CommitHash("c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0".to_string()); - filter_by!(repo, RustFilter::FunctionInBlock(crate::languages::rust::BlockType::Impl), RustFilter) - // assert_eq!(filtered_repo.commit_history.len(), 1); - // assert_eq!(filtered_repo.commit_history[0].commit_hash, "c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0"); + // option 1: takes a filter + ($self:expr, $filter:expr) => { + $self.filter_by(&$filter) + }; + // option 2: takes a PLFilter variant + ($self:expr, $pl_filter:expr, $cfg:literal) => { + $self.filter_by(&Filter::PLFilter($pl_filter)) + }; + // option 3: takes a language specific filter ie RustFilter and a language ie Rust + ($self:expr, $rust_filter:expr, $language:ident) => {{ + use crate::languages::LanguageFilter; + $self.filter_by(&Filter::PLFilter(LanguageFilter::$language($rust_filter))) + }}; } impl Display for FunctionHistory { From e4c4d9ca6a1395d9965dd7b37ac4ab2c36274f5d Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Fri, 28 Oct 2022 14:14:29 +0000 Subject: [PATCH 089/172] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3040ed79..9971d589 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ All notable changes to this project will be documented in this file. - Non proggraming languge (pl) filters addded back - Added ability to search in all supported languages - Pl filters now working very messy and boilerplatety +- Fixed bug where I didnt understand how cfg-if works, also filter_by macro works just neeeds docs ### Tui From 93672a5a3063ea7c47cf7ec4afb5a46700e50fd0 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Fri, 28 Oct 2022 10:15:32 -0400 Subject: [PATCH 090/172] cargo clippied last commit --- git-function-history-lib/src/languages/ruby.rs | 5 +---- git-function-history-lib/src/types.rs | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index ef82d54b..3cdfb042 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -268,10 +268,7 @@ pub enum RubyFilter { impl RubyFilter { pub fn matches(&self, function: &RubyFunction) -> bool { match self { - Self::FunctionInClass(name) => match &function.class { - Some(class) => *name == class.name, - None => false, - }, + Self::FunctionInClass(name) => function.class.as_ref().map_or(false, |class| *name == class.name), Self::FunctionWithParameter(name) => function.args.contains(name), } } diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index ee2193c2..a0dd32d8 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -462,7 +462,7 @@ macro_rules! filter_by { }; // option 3: takes a language specific filter ie RustFilter and a language ie Rust ($self:expr, $rust_filter:expr, $language:ident) => {{ - use crate::languages::LanguageFilter; + use $crate::languages::LanguageFilter; $self.filter_by(&Filter::PLFilter(LanguageFilter::$language($rust_filter))) }}; } From de1956104448b053dd98d4944e179869ce01b4d0 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 30 Oct 2022 08:34:25 -0400 Subject: [PATCH 091/172] added some more specific error messages --- .github/workflows/cargo_clippy_lib.yml | 2 +- git-function-history-lib/src/lib.rs | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cargo_clippy_lib.yml b/.github/workflows/cargo_clippy_lib.yml index 1ed83b42..57f5dde9 100644 --- a/.github/workflows/cargo_clippy_lib.yml +++ b/.github/workflows/cargo_clippy_lib.yml @@ -15,7 +15,7 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} toolchain: nightly - args: --features unstable, c_lang -p git_function_history + args: -p git_function_history --features unstable, c_lang nightly-clang-test: runs-on: ubuntu-latest steps: diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 12b6eb91..b4b3ff0a 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -370,6 +370,9 @@ fn find_function_in_commit_with_filetype( Err(String::from_utf8_lossy(&command.stderr))?; } let file_list = String::from_utf8_lossy(&command.stdout).to_string(); + if file_list.is_empty() { + return Err(format!("no files found for commit {} in git ouput", commit))?; + } for file in file_list.split('\n') { match filetype { FileFilterType::Relative(ref path) => { @@ -443,7 +446,9 @@ fn find_function_in_commit_with_filetype( }, } } - + if files.is_empty() { + return Err(format!("no files found for commit {} in matching the languages specified", commit))?; + } let err = "no function found".to_string(); #[cfg(feature = "parellel")] let t = files.par_iter(); From 906eac3b43eff0dc3f17cb0226ee1dd6c4b403ed Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 30 Oct 2022 08:42:33 -0400 Subject: [PATCH 092/172] printing new error messages in tests --- .github/workflows/cargo_clippy_lib.yml | 4 ++-- git-function-history-lib/src/lib.rs | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cargo_clippy_lib.yml b/.github/workflows/cargo_clippy_lib.yml index 57f5dde9..9abbe1a1 100644 --- a/.github/workflows/cargo_clippy_lib.yml +++ b/.github/workflows/cargo_clippy_lib.yml @@ -15,7 +15,7 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} toolchain: nightly - args: -p git_function_history --features unstable, c_lang + args: -p git_function_history --features unstable --features c_lang nightly-clang-test: runs-on: ubuntu-latest steps: @@ -27,7 +27,7 @@ jobs: override: true - name: test run: | - cargo +nightly test -p git_function_history --features unstable, c_lang -- --nocapture + cargo +nightly test -p git_function_history --features unstable --features c_lang -- --nocapture test-clang: runs-on: ubuntu-latest diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index b4b3ff0a..aee631ed 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -732,6 +732,12 @@ mod tests { ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); + match &t { + Ok(functions) => { + println!("{:?}", functions); + } + Err(e) => println!("{}", e), + } assert!(t.is_ok()); } From 12a428ace6b5143b417b05e4fd90cb2021e621cc Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 30 Oct 2022 17:18:19 -0400 Subject: [PATCH 093/172] did some more java support nothing changed but maybee a bit closer and more messy --- .../src/languages/java.rs | 50 +++++++++++++++++-- .../src/languages/ruby.rs | 5 +- git-function-history-lib/src/lib.rs | 5 +- 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/git-function-history-lib/src/languages/java.rs b/git-function-history-lib/src/languages/java.rs index d3212a75..eb13dde2 100644 --- a/git-function-history-lib/src/languages/java.rs +++ b/git-function-history-lib/src/languages/java.rs @@ -132,11 +132,12 @@ fn extract_methods_from_class_item( let mut methods = Vec::new(); match item { javaparser::parse::tree::ClassBodyItem::Method(method) => { - // println!("{:#?}", method); + println!("{:#?}", method); + println!("Found method: {}", method.name.fragment); if method.name.fragment == name { - let methdef = javaparser::analyze::build::method::build(method); + // let methdef = javaparser::analyze::build::method::build(method); // let def = javaparser::extract::Definition::Method(methdef); - println!("{:#?}", methdef.span_opt.map(|s| s.fragment)); + // println!("{:#?}", methdef.span_opt.map(|s| s.fragment)); // println!("{:#?}", methdef); let args = vec![]; // method @@ -147,9 +148,48 @@ fn extract_methods_from_class_item( // let body = method.body.to_string(); // let lines = (method.line, method.line + body.lines().count()); // println!("{:#?}", method); - + // method. // to find the the bottom of the class see if block_opt is some then find the span of the last block find the first } after that and then find the line number of that + let mut top = 0; + method.modifiers.iter().for_each(|m| { + //match the modifier to extract the line number + match m { + javaparser::parse::tree::Modifier::Keyword(k) => { + top = k.name.line; + } + javaparser::parse::tree::Modifier::Annotated(a) => { + match a { + javaparser::parse::tree::Annotated::Normal(n) => { + n.params.iter().for_each(|p| { + if p.name.line > top { + top = p.name.line; + } + }); + } + javaparser::parse::tree::Annotated::Marker(m) => { + // top = m.name.line; + } + javaparser::parse::tree::Annotated::Single(s) => { + // top = s.name.line; + } + } + } + } + }); + if top == 0 { + top = match method.return_type.span_opt() { + Some(s) => s.line, + None => return Err("could not find top of method")?, + } + } + let mut bottom = 0; // to find the top of the class find the first { before the method and then find the line number of that first check modifiers if not use return type + + if let Some(b) = &method.block_opt { + // find the last block and then find the line number of the first } after that + } + // if there is no block then find the line number of + let class = Vec::new(); methods.push(JavaFunction::new( "test".to_string(), @@ -252,7 +292,7 @@ mod java_test { @Company public class Test { void main(String[] args) { - System.out.println("Hello, World"); + // System.out.println("Hello, World"); } } "#; diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 3cdfb042..3db00306 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -268,7 +268,10 @@ pub enum RubyFilter { impl RubyFilter { pub fn matches(&self, function: &RubyFunction) -> bool { match self { - Self::FunctionInClass(name) => function.class.as_ref().map_or(false, |class| *name == class.name), + Self::FunctionInClass(name) => function + .class + .as_ref() + .map_or(false, |class| *name == class.name), Self::FunctionWithParameter(name) => function.args.contains(name), } } diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index aee631ed..8fdc7fd3 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -447,7 +447,10 @@ fn find_function_in_commit_with_filetype( } } if files.is_empty() { - return Err(format!("no files found for commit {} in matching the languages specified", commit))?; + return Err(format!( + "no files found for commit {} in matching the languages specified", + commit + ))?; } let err = "no function found".to_string(); #[cfg(feature = "parellel")] From b2a3f445b35e36d1f9fd417e307595e3c013f925 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 30 Oct 2022 21:09:37 -0400 Subject: [PATCH 094/172] go added more filters for parameters , ruby added filter for superclass --- git-function-history-lib/src/languages/go.rs | 105 +++++++++++++++--- .../src/languages/ruby.rs | 19 +++- .../src/test_functions.go | 3 +- .../src/test_functions.rb | 12 +- 4 files changed, 121 insertions(+), 18 deletions(-) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index 3818902d..2daf3949 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -1,5 +1,5 @@ use crate::impl_function_trait; -use std::{error::Error, fmt}; +use std::{collections::HashMap, error::Error, fmt}; use super::FunctionTrait; @@ -7,16 +7,33 @@ use super::FunctionTrait; pub struct GoFunction { pub(crate) name: String, pub(crate) body: String, - pub(crate) parameters: Vec, + pub(crate) parameters: GoParameter, pub(crate) returns: Option, pub(crate) lines: (usize, usize), } +#[derive(Debug, Clone)] +pub enum GoParameter { + /// type + Type(Vec), + /// (name, type) + Named(HashMap), +} + +impl GoParameter { + pub fn extend(&mut self, other: &Self) { + match (self, other) { + (Self::Type(a), Self::Type(b)) => a.extend(b.clone()), + (Self::Named(a), Self::Named(b)) => a.extend(b.clone()), + _ => {} + } + } +} impl GoFunction { - pub fn new( + pub const fn new( name: String, body: String, - parameters: Vec, + parameters: GoParameter, returns: Option, lines: (usize, usize), ) -> Self { @@ -105,14 +122,63 @@ pub(crate) fn find_function_in_file( lines.0 = start_line; lines.1 = end_line; - let parameters = func - .typ - .params - .list - .iter() - .filter_map(|p| Some(&p.tag.as_ref()?.value)) - .map(std::string::ToString::to_string) - .collect(); + // see if the first parameter has a name: + let mut parameters = func.typ.params.list.get(0).map_or_else( + || GoParameter::Type(vec![]), + |param| { + if param.name.is_empty() { + GoParameter::Type(match ¶m.typ { + gosyn::ast::Expression::Type(gosyn::ast::Type::Ident( + ident, + )) => { + vec![ident.name.name.clone()] + } + _ => { + vec![] + } + }) + } else { + let typ = match ¶m.typ { + gosyn::ast::Expression::Type(gosyn::ast::Type::Ident( + ident, + )) => ident.name.name.clone(), + + _ => String::new(), + }; + let names = param.name.iter().map(|n| n.name.clone()); + GoParameter::Named( + names.into_iter().map(|name| (name, typ.clone())).collect(), + ) + } + }, + ); + + func.typ.params.list.iter().skip(1).for_each(|param| { + if param.name.is_empty() { + if let gosyn::ast::Expression::Type(gosyn::ast::Type::Ident(ident)) = + ¶m.typ + { + if let GoParameter::Type(types) = &mut parameters { + types.push(ident.name.name.clone()); + } + } + } else { + let typ = match ¶m.typ { + gosyn::ast::Expression::Type(gosyn::ast::Type::Ident(ident)) => { + ident.name.name.clone() + } + + _ => String::new(), + }; + let names = param.name.iter().map(|n| n.name.clone()); + + if let GoParameter::Named(named) = &mut parameters { + for name in names { + named.insert(name, typ.clone()); + } + } + } + }); let returns = Some( func.typ .result @@ -150,14 +216,27 @@ pub(crate) fn find_function_in_file( #[derive(Debug, Clone, PartialEq, Eq)] pub enum GoFilter { + // refers to the type of a parameter FunctionWithParameter(String), + // refers to the name of a parameter + FunctionWithParameterName(String), FunctionWithReturnType(String), } impl GoFilter { pub fn matches(&self, func: &GoFunction) -> bool { match self { - Self::FunctionWithParameter(param) => func.parameters.iter().any(|x| x.contains(param)), + Self::FunctionWithParameter(param) => match &func.parameters { + GoParameter::Type(types) => types.iter().any(|t| t == param), + GoParameter::Named(named) => named.values().any(|t| t == param), + }, + Self::FunctionWithParameterName(param) => { + if let GoParameter::Named(named) = &func.parameters { + named.iter().any(|(name, _)| name == param) + } else { + false + } + } Self::FunctionWithReturnType(ret) => { func.returns.as_ref().map_or(false, |x| x.contains(ret)) } diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 3db00306..0819fdcf 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -109,7 +109,7 @@ pub(crate) fn find_function_in_file( Some(RubyClass { name: parser_class_name(c), line: (start_line, end_line), - superclass: None, + superclass: parse_superclass(c), top: top .lines() .map(|l| { @@ -240,6 +240,16 @@ fn parser_class_name(class: &Class) -> String { } } +fn parse_superclass(class: &Class) -> Option { + class + .superclass + .as_ref() + .and_then(|superclass| match superclass.as_ref() { + lib_ruby_parser::Node::Const(constant) => Some(constant.name.clone()), + _ => None, + }) +} + impl FunctionTrait for RubyFunction { crate::impl_function_trait!(RubyFunction); @@ -263,6 +273,7 @@ impl FunctionTrait for RubyFunction { pub enum RubyFilter { FunctionInClass(String), FunctionWithParameter(String), + FunctionWithSuperClass(String), } impl RubyFilter { @@ -273,6 +284,12 @@ impl RubyFilter { .as_ref() .map_or(false, |class| *name == class.name), Self::FunctionWithParameter(name) => function.args.contains(name), + Self::FunctionWithSuperClass(name) => function.class.as_ref().map_or(false, |class| { + class + .superclass + .as_ref() + .map_or(false, |superclass| superclass == name) + }), } } } diff --git a/git-function-history-lib/src/test_functions.go b/git-function-history-lib/src/test_functions.go index b4bc784a..fc04e29a 100644 --- a/git-function-history-lib/src/test_functions.go +++ b/git-function-history-lib/src/test_functions.go @@ -6,10 +6,11 @@ import ( ) func main() { + empty_test("1", 2, "3") fmt.Println("Hello World!") } // doc comment -func empty_test() { +func empty_test(c, a int, b string) { fmt.Println("Hello World!") } \ No newline at end of file diff --git a/git-function-history-lib/src/test_functions.rb b/git-function-history-lib/src/test_functions.rb index 41a64d1b..7381033a 100644 --- a/git-function-history-lib/src/test_functions.rb +++ b/git-function-history-lib/src/test_functions.rb @@ -4,13 +4,19 @@ def main() def empty_test() end - +class SupderDuper + def boring + end +end class - Test + Test < SupderDuper def empty_test() end def test() puts "Hello World" end -end \ No newline at end of file +end + +# def () empty_test +# end \ No newline at end of file From 499510aab204a4e1e43dd60b645e51769f678f58 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 30 Oct 2022 21:40:25 -0400 Subject: [PATCH 095/172] added a wak ton more filters also renamed other ones --- git-function-history-lib/src/languages/go.rs | 12 +- git-function-history-lib/src/languages/mod.rs | 1 + .../src/languages/python.rs | 64 ++++++--- .../src/languages/rust.rs | 126 ++++++++++++++---- git-function-history-lib/src/lib.rs | 8 +- 5 files changed, 157 insertions(+), 54 deletions(-) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index 2daf3949..e58e6299 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -217,27 +217,27 @@ pub(crate) fn find_function_in_file( #[derive(Debug, Clone, PartialEq, Eq)] pub enum GoFilter { // refers to the type of a parameter - FunctionWithParameter(String), + HasParameter(String), // refers to the name of a parameter - FunctionWithParameterName(String), - FunctionWithReturnType(String), + HasParameterName(String), + HasReturnType(String), } impl GoFilter { pub fn matches(&self, func: &GoFunction) -> bool { match self { - Self::FunctionWithParameter(param) => match &func.parameters { + Self::HasParameter(param) => match &func.parameters { GoParameter::Type(types) => types.iter().any(|t| t == param), GoParameter::Named(named) => named.values().any(|t| t == param), }, - Self::FunctionWithParameterName(param) => { + Self::HasParameterName(param) => { if let GoParameter::Named(named) = &func.parameters { named.iter().any(|(name, _)| name == param) } else { false } } - Self::FunctionWithReturnType(ret) => { + Self::HasReturnType(ret) => { func.returns.as_ref().map_or(false, |x| x.contains(ret)) } } diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index a24569f2..407e66f7 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -4,6 +4,7 @@ use std::{ fmt::{self, Display}, }; // TODO: lisp/scheme js, java?(https://github.com/tanin47/javaparser.rs) php?(https://docs.rs/tagua-parser/0.1.0/tagua_parser/) +// TODO: make a macro for generating filters use self::{python::PythonFunction, ruby::RubyFunction, rust::RustFunction}; #[cfg(feature = "c_lang")] diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index ccc6ad3a..68b0900b 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -16,7 +16,7 @@ pub struct PythonFunction { pub(crate) body: String, // parameters: Params, pub(crate) parameters: Vec, - pub(crate) parent: Vec, + pub(crate) parent: Vec, pub(crate) decorators: Vec, pub(crate) class: Option, pub(crate) lines: (usize, usize), @@ -41,13 +41,13 @@ impl fmt::Display for PythonFunction { } } -#[derive(Debug, Clone)] -pub struct Params { - args: Vec, - kwargs: Vec, - varargs: Option, - varkwargs: Option, -} +// #[derive(Debug, Clone)] +// pub struct Params { +// args: Vec, +// kwargs: Vec, +// varargs: Option, +// varkwargs: Option, +// } #[derive(Debug, Clone)] pub struct Class { pub(crate) name: String, @@ -57,14 +57,14 @@ pub struct Class { pub(crate) decorators: Vec, } #[derive(Debug, Clone)] -pub struct ParentFunction { +pub struct PythonParentFunction { pub(crate) name: String, pub(crate) top: String, pub(crate) bottom: String, pub(crate) lines: (usize, usize), pub(crate) parameters: Vec, pub(crate) decorators: Vec, - pub(crate) class: Option, + // pub(crate) class: Option, pub(crate) returns: Option, } @@ -201,6 +201,7 @@ fn fun_name( } fn get_functions<'a>( + // TODO: get parent functions and classes stmt: Located, next_stmt: Option<&Located>, functions: &mut Vec<(StatementType, (Location, Location))>, @@ -305,34 +306,57 @@ fn get_functions<'a>( #[derive(Debug, Clone, PartialEq, Eq)] pub enum PythonFilter { /// when you want to filter by function that are in a specific class - FunctionInClass(String), + InClass(String), /// when you want filter by a function that has a parent function of a specific name - FunctionWithParent(String), + HasParentFunction(String), /// when you want to filter by a function that has a has a specific return type - FunctionWithReturnType(String), + HasReturnType(String), /// when you want to filter by a function that has a specific parameter name - FunctionWithParameterName(String), + HasParameterName(String), /// when you want to filter by a function that has a specific decorator - FunctionWithDecorator(String), + HasDecorator(String), + /// when you want to filter by a function thats class has a specific decorator + HasClasswithDecorator(String), + /// when you want to filter by a function that's parent function has a specific decorator + HasParentFunctionwithDecorator(String), + /// when you want to filter by a function that's parent function has a specific parameter name + HasParentFunctionwithParameterName(String), + /// when you want to filter by a function that's parent function has a specific return type + HasParentFunctionwithReturnType(String), } impl PythonFilter { pub fn matches(&self, function: &PythonFunction) -> bool { match self { - Self::FunctionInClass(class) => { + Self::InClass(class) => { function.class.as_ref().map_or(false, |x| x.name == *class) } - Self::FunctionWithParent(parent) => function.parent.iter().any(|x| x.name == *parent), - Self::FunctionWithReturnType(return_type) => function + Self::HasParentFunction(parent) => function.parent.iter().any(|x| x.name == *parent), + Self::HasReturnType(return_type) => function .returns .as_ref() .map_or(false, |x| x == return_type), - Self::FunctionWithParameterName(parameter_name) => { + Self::HasParameterName(parameter_name) => { function.parameters.iter().any(|x| x == parameter_name) } - Self::FunctionWithDecorator(decorator) => { + Self::HasDecorator(decorator) => { function.decorators.iter().any(|x| x == decorator) } + Self::HasClasswithDecorator(decorator) => { + function.class.as_ref().map_or(false, |x| { + x.decorators.iter().any(|x| x == decorator) + }) + } + Self::HasParentFunctionwithDecorator(decorator) => function + .parent + .iter() + .any(|x| x.decorators.iter().any(|x| x == decorator)), + Self::HasParentFunctionwithParameterName(parameter_name) => function.parent.iter().any( + |x| x.parameters.iter().any(|x| x == parameter_name), + ), + Self::HasParentFunctionwithReturnType(return_type) => function.parent.iter().any( + |x| x.returns.as_ref().map_or(false, |x| x == return_type), + ), } } } diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 4aaa00e2..361e9af4 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -18,7 +18,7 @@ pub struct RustFunction { /// is the function in a block ie `impl` `trait` etc pub(crate) block: Option, /// optional parent functions - pub(crate) function: Vec, + pub(crate) function: Vec, /// The line number the function starts and ends on pub(crate) lines: (usize, usize), /// The lifetime of the function @@ -37,7 +37,7 @@ pub struct RustFunction { impl RustFunction { /// get the parent functions - pub fn get_parent_function(&self) -> Vec { + pub fn get_parent_function(&self) -> Vec { self.function.clone() } @@ -70,7 +70,7 @@ impl fmt::Display for RustFunction { /// This is used for the functions that are being looked up themeselves but store an outer function that may aontains a function that is being looked up. #[derive(Debug, Clone)] -pub struct FunctionBlock { +pub struct RustParentFunction { /// The name of the function (parent function) pub(crate) name: String, /// what the signature of the function is @@ -93,7 +93,7 @@ pub struct FunctionBlock { pub(crate) doc_comments: Vec, } -impl FunctionBlock { +impl RustParentFunction { /// get the metadata for this block ie the name of the block, the type of block, the line number the block starts and ends pub fn get_metadata(&self) -> HashMap { let mut map = HashMap::new(); @@ -221,7 +221,7 @@ pub(crate) fn find_function_in_file( let stuff = get_stuff(f, file_contents, &map); let generics = get_genrerics_and_lifetime(f); let mut parent = f.syntax().parent(); - let mut parent_fn: Vec = Vec::new(); + let mut parent_fn: Vec = Vec::new(); let mut parent_block = None; while let Some(p) = parent.into_iter().next() { if p.kind() == SyntaxKind::SOURCE_FILE { @@ -279,7 +279,7 @@ pub(crate) fn find_function_in_file( let stuff = get_stuff(&function, file_contents, &map); let generics = get_genrerics_and_lifetime(&function); let attr = get_doc_comments_and_attrs(&function); - parent_fn.push(FunctionBlock { + parent_fn.push(RustParentFunction { name: function.name().unwrap().to_string(), lifetime: generics.1, generics: generics.0, @@ -459,46 +459,68 @@ fn get_doc_comments_and_attrs(block: &T) -> (Vec, Vec #[derive(Debug, Clone, PartialEq, Eq)] pub enum RustFilter { /// when you want to filter by function that are in a specific block (impl, trait, extern) - FunctionInBlock(BlockType), + InBlock(BlockType), /// when you want filter by a function that has a parent function of a specific name - FunctionWithParent(String), + HasParentFunction(String), /// when you want to filter by a function that has a has a specific return type - FunctionWithReturnType(String), + HasReturnType(String), /// when you want to filter by a function that has a specific parameter type - FunctionWithParameterType(String), + HasParameterType(String), /// when you want to filter by a function that has a specific parameter name - FunctionWithParameterName(String), + HasParameterName(String), /// when you want to filter by a function that has a specific lifetime - FunctionWithLifetime(String), + HasLifetime(String), /// when you want to filter by a function that has a specific generic with name - FunctionWithGeneric(String), + HasGeneric(String), /// when you want to filter by a function that has a specific attribute - FunctionWithAttribute(String), + HasAttribute(String), /// when you want to filter by a function that has or contains a specific doc comment - FunctionWithDocComment(String), + HasDocComment(String), + /// when you want to filter by a function that's block has a specific attribute + BlockHasAttribute(String), + /// when you want to filter by a function that's block has a specific doc comment + BlockHasDocComment(String), + /// when you want to filter by a function that's block has a specific lifetime + BlockHasLifetime(String), + /// when you want to filter by a function that's block has a specific generic with name + BlockHasGeneric(String), + /// when you want to filter by a function that's parent function has a specific attribute + ParentFunctionHasAttribute(String), + /// when you want to filter by a function that's parent function has a specific doc comment + ParentFunctionHasDocComment(String), + /// when you want to filter by a function that's parent function has a specific lifetime + ParentFunctionHasLifetime(String), + /// when you want to filter by a function that's parent function has a specific generic with name + ParentFunctionHasGeneric(String), + /// when you want to filter by a function that's parent function has a specific return type + ParentFunctionHasReturnType(String), + /// when you want to filter by a function that's parent function has a specific parameter type + ParentFunctionHasParameterType(String), + /// when you want to filter by a function that's parent function has a specific parameter name + ParentFunctionHasParameterName(String), } impl RustFilter { pub fn matches(&self, function: &RustFunction) -> bool { match self { - Self::FunctionInBlock(block_type) => function + Self::InBlock(block_type) => function .block .as_ref() .map_or(false, |block| block.block_type == *block_type), - Self::FunctionWithParent(parent) => function.function.iter().any(|f| f.name == *parent), - Self::FunctionWithReturnType(return_type) => { + Self::HasParentFunction(parent) => function.function.iter().any(|f| f.name == *parent), + Self::HasReturnType(return_type) => { function.return_type == Some(return_type.to_string()) } - Self::FunctionWithParameterType(parameter_type) => { + Self::HasParameterType(parameter_type) => { function.arguments.values().any(|x| x == parameter_type) } - Self::FunctionWithParameterName(parameter_name) => { + Self::HasParameterName(parameter_name) => { function.arguments.keys().any(|x| x == parameter_name) } - Self::FunctionWithLifetime(lifetime) => function.lifetime.contains(lifetime), - Self::FunctionWithGeneric(generic) => function.generics.contains(generic), - Self::FunctionWithAttribute(attribute) => function.attributes.contains(attribute), - Self::FunctionWithDocComment(comment) => { + Self::HasLifetime(lifetime) => function.lifetime.contains(lifetime), + Self::HasGeneric(generic) => function.generics.contains(generic), + Self::HasAttribute(attribute) => function.attributes.contains(attribute), + Self::HasDocComment(comment) => { function .doc_comments .iter() @@ -506,6 +528,62 @@ impl RustFilter { .count() > 0 } + Self::BlockHasAttribute(attribute) => { + function.block.as_ref().map_or(false, |block| { + block.attributes.contains(attribute) + }) + } + Self::BlockHasDocComment(comment) => { + function.block.as_ref().map_or(false, |block| { + block + .doc_comments + .iter() + .filter(|doc| comment.contains(*doc)) + .count() + > 0 + }) + } + Self::BlockHasLifetime(lifetime) => { + function.block.as_ref().map_or(false, |block| { + block.lifetime.contains(lifetime) + }) + } + Self::BlockHasGeneric(generic) => { + function.block.as_ref().map_or(false, |block| { + block.generics.contains(generic) + }) + } + Self::ParentFunctionHasAttribute(attribute) => { + function.function.iter().any(|f| f.attributes.contains(attribute)) + } + Self::ParentFunctionHasDocComment(comment) => { + function.function.iter().any(|f| { + f.doc_comments + .iter() + .filter(|doc| comment.contains(*doc)) + .count() + > 0 + }) + } + Self::ParentFunctionHasLifetime(lifetime) => { + function.function.iter().any(|f| f.lifetime.contains(lifetime)) + } + Self::ParentFunctionHasGeneric(generic) => { + function.function.iter().any(|f| f.generics.contains(generic)) + } + Self::ParentFunctionHasReturnType(return_type) => { + function.function.iter().any(|f| f.return_type == Some(return_type.to_string())) + } + Self::ParentFunctionHasParameterType(parameter_type) => { + function.function.iter().any(|f| { + f.arguments.values().any(|x| x == parameter_type) + }) + } + Self::ParentFunctionHasParameterName(parameter_name) => { + function.function.iter().any(|f| { + f.arguments.keys().any(|x| x == parameter_name) + }) + } } } } diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 8fdc7fd3..cd48db22 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -776,7 +776,7 @@ mod tests { }; now = Utc::now(); let new_output = output.filter_by(&Filter::PLFilter(LanguageFilter::Rust( - rust::RustFilter::FunctionWithParameterType(String::from("String")), + rust::RustFilter::HasParameterType(String::from("String")), ))); after = Utc::now() - now; println!("time taken to filter {}", after.num_seconds()); @@ -785,7 +785,7 @@ mod tests { Err(e) => println!("{e}"), } let new_output = output.filter_by(&Filter::PLFilter(LanguageFilter::Rust( - rust::RustFilter::FunctionInBlock(BlockType::Extern), + rust::RustFilter::InBlock(BlockType::Extern), ))); after = Utc::now() - now; println!("time taken to filter {}", after.num_seconds()); @@ -802,7 +802,7 @@ mod tests { get_function_history!(name = "empty_test").expect("Failed to get function history"); let f1 = filter_by!( repo, - RustFilter::FunctionInBlock(crate::languages::rust::BlockType::Impl), + RustFilter::InBlock(crate::languages::rust::BlockType::Impl), Rust ); match f1 { @@ -819,7 +819,7 @@ mod tests { } let f3 = filter_by!( repo, - LanguageFilter::Rust(RustFilter::FunctionInBlock( + LanguageFilter::Rust(RustFilter::InBlock( crate::languages::rust::BlockType::Impl )), 1 From 52178e201d721f711ec258bb93420f0eb350a2f2 Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Mon, 31 Oct 2022 03:06:05 -0400 Subject: [PATCH 096/172] playing around memoization --- git-function-history-lib/Cargo.toml | 6 ++- git-function-history-lib/src/languages/c.rs | 4 ++ git-function-history-lib/src/languages/go.rs | 5 +- .../src/languages/java.rs | 5 +- git-function-history-lib/src/languages/mod.rs | 2 +- .../src/languages/python.rs | 5 +- .../src/languages/ruby.rs | 5 +- .../src/languages/rust.rs | 5 +- git-function-history-lib/src/lib.rs | 53 ++++++++++++------- 9 files changed, 63 insertions(+), 27 deletions(-) diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 13c0cefe..c51c77c3 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -16,10 +16,12 @@ unstable = ["dep:gosyn", "dep:javaparser"] [dependencies] chrono = "0.4.22" -ra_ap_syntax = "0.0.134" +ra_ap_syntax = "0.0.137" rayon = { version = "1.5.3", optional = true } rustpython-parser = "0.1.2" lib-ruby-parser = "3.0.12" gosyn = {version = "0.1.1", optional = true} javaparser = {git = "https://github.com/tanin47/javaparser.rs", optional = true} -cfg-if = "1.0.0" \ No newline at end of file +cfg-if = "1.0.0" +# lazy_static = "1.4.0" +cached = "0.40.0" \ No newline at end of file diff --git a/git-function-history-lib/src/languages/c.rs b/git-function-history-lib/src/languages/c.rs index d8829b45..acc821d4 100644 --- a/git-function-history-lib/src/languages/c.rs +++ b/git-function-history-lib/src/languages/c.rs @@ -64,6 +64,10 @@ pub struct ParentFunction { pub(crate) returns: Option, } #[inline] +/* +use cached::proc_macro::cached; +#[cached(result = true)] +*/ pub(crate) fn find_function_in_file( file_contents: &str, name: &str, diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index e58e6299..cfccf4f3 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -71,7 +71,10 @@ impl FunctionTrait for GoFunction { (start, end) } } - +/* +use cached::proc_macro::cached; +#[cached(result = true)] +*/ pub(crate) fn find_function_in_file( file_contents: &str, name: &str, diff --git a/git-function-history-lib/src/languages/java.rs b/git-function-history-lib/src/languages/java.rs index eb13dde2..1b81aaf7 100644 --- a/git-function-history-lib/src/languages/java.rs +++ b/git-function-history-lib/src/languages/java.rs @@ -68,7 +68,10 @@ pub enum JavaBlockType { Enum, Interface, } - +/* +use cached::proc_macro::cached; +#[cached(result = true)] +*/ pub(crate) fn find_function_in_file( file_contents: &str, name: &str, diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 407e66f7..486ee07f 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -12,7 +12,7 @@ use self::c::CFunction; #[cfg(feature = "unstable")] use go::GoFunction; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Language { /// The python language Python, diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 68b0900b..aeea3fe6 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -67,7 +67,10 @@ pub struct PythonParentFunction { // pub(crate) class: Option, pub(crate) returns: Option, } - +/* +use cached::proc_macro::cached; +#[cached(result = true)] +*/ pub(crate) fn find_function_in_file( file_contents: &str, name: &str, diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 0819fdcf..c3853bb0 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -59,7 +59,10 @@ pub struct RubyClass { pub top: String, pub bottom: String, } - +/* +use cached::proc_macro::cached; +#[cached(result = true)] +*/ pub(crate) fn find_function_in_file( file_contents: &str, name: &str, diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 361e9af4..4b7ff4c7 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -197,7 +197,10 @@ impl fmt::Display for BlockType { } } } - +/* +use cached::proc_macro::cached; +#[cached(result = true)] +*/ #[allow(clippy::too_many_lines)] // TODO: split this function into smaller functions pub(crate) fn find_function_in_file( diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index cd48db22..01b91494 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -18,11 +18,18 @@ pub mod languages; /// Different types that can extracted from the result of `get_function_history`. pub mod types; +// lazy_static::lazy_static! { +// /// saves already parsed files +// /// key: content of file and language +// /// value: parsed file +// pub static ref MEMOIZE: Mutex> = Mutex::new(HashMap::new()); +// } + use languages::{rust, LanguageFilter, PythonFile, RubyFile, RustFile}; #[cfg(feature = "parallel")] use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; -use std::{error::Error, process::Command}; +use std::{error::Error, process::Command, collections::HashMap, sync::Mutex}; #[cfg(feature = "c_lang")] use languages::CFile; @@ -466,6 +473,9 @@ fn find_function_in_commit_with_filetype( Ok(returns) } + +// #[cached] +// #[cached(result = true)] fn find_function_in_file_with_commit( commit: &str, file_path: &str, @@ -473,73 +483,78 @@ fn find_function_in_file_with_commit( langs: Language, ) -> Result> { let fc = find_file_in_commit(commit, file_path)?; - match langs { + // if let Some(file) = MEMOIZE.lock()?.get(&fc) { + // return Ok(file.clone()); + // } + let file = match langs { Language::Rust => { let functions = rust::find_function_in_file(&fc, name)?; - Ok(FileType::Rust(RustFile::new( + FileType::Rust(RustFile::new( file_path.to_string(), functions, - ))) + )) } #[cfg(feature = "c_lang")] Language::C => { let functions = languages::c::find_function_in_file(&fc, name)?; - Ok(FileType::C(CFile::new(file_path.to_string(), functions))) + FileType::C(CFile::new(file_path.to_string(), functions)) } #[cfg(feature = "unstable")] Language::Go => { let functions = languages::go::find_function_in_file(&fc, name)?; - Ok(FileType::Go(GoFile::new(file_path.to_string(), functions))) + FileType::Go(GoFile::new(file_path.to_string(), functions)) } Language::Python => { let functions = languages::python::find_function_in_file(&fc, name)?; - Ok(FileType::Python(PythonFile::new( + FileType::Python(PythonFile::new( file_path.to_string(), functions, - ))) + )) } Language::Ruby => { let functions = languages::ruby::find_function_in_file(&fc, name)?; - Ok(FileType::Ruby(RubyFile::new( + FileType::Ruby(RubyFile::new( file_path.to_string(), functions, - ))) + )) } Language::All => match file_path.split('.').last() { Some("rs") => { let functions = rust::find_function_in_file(&fc, name)?; - Ok(FileType::Rust(RustFile::new( + FileType::Rust(RustFile::new( file_path.to_string(), functions, - ))) + )) } #[cfg(feature = "c_lang")] Some("c" | "h") => { let functions = languages::c::find_function_in_file(&fc, name)?; - Ok(FileType::C(CFile::new(file_path.to_string(), functions))) + FileType::C(CFile::new(file_path.to_string(), functions)) } Some("py") => { let functions = languages::python::find_function_in_file(&fc, name)?; - Ok(FileType::Python(PythonFile::new( + FileType::Python(PythonFile::new( file_path.to_string(), functions, - ))) + )) } #[cfg(feature = "unstable")] Some("go") => { let functions = languages::go::find_function_in_file(&fc, name)?; - Ok(FileType::Go(GoFile::new(file_path.to_string(), functions))) + FileType::Go(GoFile::new(file_path.to_string(), functions)) } Some("rb") => { let functions = languages::ruby::find_function_in_file(&fc, name)?; - Ok(FileType::Ruby(RubyFile::new( + FileType::Ruby(RubyFile::new( file_path.to_string(), functions, - ))) + )) } _ => Err("unknown file type")?, }, - } + }; + // MEMOIZE.lock()?.insert(fc, file.clone()); + Ok(file) } trait UnwrapToError { From 48c680af7ca368abfe147758fdb1d213a854bfe7 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 2 Nov 2022 14:40:14 -0400 Subject: [PATCH 097/172] added caching feature fixed some cfg features being misspelled --- git-function-history-lib/Cargo.toml | 6 +- git-function-history-lib/src/languages/go.rs | 4 +- git-function-history-lib/src/languages/mod.rs | 4 +- .../src/languages/python.rs | 31 ++-- .../src/languages/rust.rs | 107 ++++++------- git-function-history-lib/src/lib.rs | 151 +++++++++++------- 6 files changed, 161 insertions(+), 142 deletions(-) diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index c51c77c3..5873db5d 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -9,10 +9,13 @@ categories = ["tools", "git"] description = "show function history from git" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] +# default = ["parallel", "unstable", "cache"] +# default = ["parallel", "unstable"] default = ["parallel"] parallel = ["dep:rayon"] c_lang = [] unstable = ["dep:gosyn", "dep:javaparser"] +cache = ["dep:cached"] [dependencies] chrono = "0.4.22" @@ -23,5 +26,4 @@ lib-ruby-parser = "3.0.12" gosyn = {version = "0.1.1", optional = true} javaparser = {git = "https://github.com/tanin47/javaparser.rs", optional = true} cfg-if = "1.0.0" -# lazy_static = "1.4.0" -cached = "0.40.0" \ No newline at end of file +cached = {version = "0.40.0", optional = true} \ No newline at end of file diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index cfccf4f3..06b25e64 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -240,9 +240,7 @@ impl GoFilter { false } } - Self::HasReturnType(ret) => { - func.returns.as_ref().map_or(false, |x| x.contains(ret)) - } + Self::HasReturnType(ret) => func.returns.as_ref().map_or(false, |x| x.contains(ret)), } } } diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 486ee07f..c99c415f 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -79,8 +79,8 @@ impl fmt::Display for Language { pub mod c; #[cfg(feature = "unstable")] pub mod go; -#[cfg(feature = "unstable")] -pub mod java; +// #[cfg(feature = "unstable")] +// pub mod java; pub mod python; pub mod ruby; pub mod rust; diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index aeea3fe6..69060fa2 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -331,9 +331,7 @@ pub enum PythonFilter { impl PythonFilter { pub fn matches(&self, function: &PythonFunction) -> bool { match self { - Self::InClass(class) => { - function.class.as_ref().map_or(false, |x| x.name == *class) - } + Self::InClass(class) => function.class.as_ref().map_or(false, |x| x.name == *class), Self::HasParentFunction(parent) => function.parent.iter().any(|x| x.name == *parent), Self::HasReturnType(return_type) => function .returns @@ -342,24 +340,23 @@ impl PythonFilter { Self::HasParameterName(parameter_name) => { function.parameters.iter().any(|x| x == parameter_name) } - Self::HasDecorator(decorator) => { - function.decorators.iter().any(|x| x == decorator) - } - Self::HasClasswithDecorator(decorator) => { - function.class.as_ref().map_or(false, |x| { - x.decorators.iter().any(|x| x == decorator) - }) - } + Self::HasDecorator(decorator) => function.decorators.iter().any(|x| x == decorator), + Self::HasClasswithDecorator(decorator) => function + .class + .as_ref() + .map_or(false, |x| x.decorators.iter().any(|x| x == decorator)), Self::HasParentFunctionwithDecorator(decorator) => function .parent .iter() .any(|x| x.decorators.iter().any(|x| x == decorator)), - Self::HasParentFunctionwithParameterName(parameter_name) => function.parent.iter().any( - |x| x.parameters.iter().any(|x| x == parameter_name), - ), - Self::HasParentFunctionwithReturnType(return_type) => function.parent.iter().any( - |x| x.returns.as_ref().map_or(false, |x| x == return_type), - ), + Self::HasParentFunctionwithParameterName(parameter_name) => function + .parent + .iter() + .any(|x| x.parameters.iter().any(|x| x == parameter_name)), + Self::HasParentFunctionwithReturnType(return_type) => function + .parent + .iter() + .any(|x| x.returns.as_ref().map_or(false, |x| x == return_type)), } } } diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 4b7ff4c7..c8d27dc7 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -531,62 +531,57 @@ impl RustFilter { .count() > 0 } - Self::BlockHasAttribute(attribute) => { - function.block.as_ref().map_or(false, |block| { - block.attributes.contains(attribute) - }) - } - Self::BlockHasDocComment(comment) => { - function.block.as_ref().map_or(false, |block| { - block - .doc_comments - .iter() - .filter(|doc| comment.contains(*doc)) - .count() - > 0 - }) - } - Self::BlockHasLifetime(lifetime) => { - function.block.as_ref().map_or(false, |block| { - block.lifetime.contains(lifetime) - }) - } - Self::BlockHasGeneric(generic) => { - function.block.as_ref().map_or(false, |block| { - block.generics.contains(generic) - }) - } - Self::ParentFunctionHasAttribute(attribute) => { - function.function.iter().any(|f| f.attributes.contains(attribute)) - } - Self::ParentFunctionHasDocComment(comment) => { - function.function.iter().any(|f| { - f.doc_comments - .iter() - .filter(|doc| comment.contains(*doc)) - .count() - > 0 - }) - } - Self::ParentFunctionHasLifetime(lifetime) => { - function.function.iter().any(|f| f.lifetime.contains(lifetime)) - } - Self::ParentFunctionHasGeneric(generic) => { - function.function.iter().any(|f| f.generics.contains(generic)) - } - Self::ParentFunctionHasReturnType(return_type) => { - function.function.iter().any(|f| f.return_type == Some(return_type.to_string())) - } - Self::ParentFunctionHasParameterType(parameter_type) => { - function.function.iter().any(|f| { - f.arguments.values().any(|x| x == parameter_type) - }) - } - Self::ParentFunctionHasParameterName(parameter_name) => { - function.function.iter().any(|f| { - f.arguments.keys().any(|x| x == parameter_name) - }) - } + Self::BlockHasAttribute(attribute) => function + .block + .as_ref() + .map_or(false, |block| block.attributes.contains(attribute)), + Self::BlockHasDocComment(comment) => function.block.as_ref().map_or(false, |block| { + block + .doc_comments + .iter() + .filter(|doc| comment.contains(*doc)) + .count() + > 0 + }), + Self::BlockHasLifetime(lifetime) => function + .block + .as_ref() + .map_or(false, |block| block.lifetime.contains(lifetime)), + Self::BlockHasGeneric(generic) => function + .block + .as_ref() + .map_or(false, |block| block.generics.contains(generic)), + Self::ParentFunctionHasAttribute(attribute) => function + .function + .iter() + .any(|f| f.attributes.contains(attribute)), + Self::ParentFunctionHasDocComment(comment) => function.function.iter().any(|f| { + f.doc_comments + .iter() + .filter(|doc| comment.contains(*doc)) + .count() + > 0 + }), + Self::ParentFunctionHasLifetime(lifetime) => function + .function + .iter() + .any(|f| f.lifetime.contains(lifetime)), + Self::ParentFunctionHasGeneric(generic) => function + .function + .iter() + .any(|f| f.generics.contains(generic)), + Self::ParentFunctionHasReturnType(return_type) => function + .function + .iter() + .any(|f| f.return_type == Some(return_type.to_string())), + Self::ParentFunctionHasParameterType(parameter_type) => function + .function + .iter() + .any(|f| f.arguments.values().any(|x| x == parameter_type)), + Self::ParentFunctionHasParameterName(parameter_name) => function + .function + .iter() + .any(|f| f.arguments.keys().any(|x| x == parameter_name)), } } } diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 01b91494..b110eb3f 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -18,18 +18,14 @@ pub mod languages; /// Different types that can extracted from the result of `get_function_history`. pub mod types; -// lazy_static::lazy_static! { -// /// saves already parsed files -// /// key: content of file and language -// /// value: parsed file -// pub static ref MEMOIZE: Mutex> = Mutex::new(HashMap::new()); -// } - +// static mut file_count: usize = 0; +#[cfg(feature = "cache")] +use cached::proc_macro::cached; use languages::{rust, LanguageFilter, PythonFile, RubyFile, RustFile}; #[cfg(feature = "parallel")] use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; -use std::{error::Error, process::Command, collections::HashMap, sync::Mutex}; +use std::{error::Error, process::Command}; #[cfg(feature = "c_lang")] use languages::CFile; @@ -460,103 +456,133 @@ fn find_function_in_commit_with_filetype( ))?; } let err = "no function found".to_string(); - #[cfg(feature = "parellel")] - let t = files.par_iter(); - #[cfg(not(feature = "parellel"))] - let t = files.iter(); - let returns: Vec = t - .filter_map(|file| find_function_in_file_with_commit(commit, file, name, langs).ok()) - .collect(); - if returns.is_empty() { + // organize the files into hierarchical structure of directories (vector of vectors) by splitting the path + let mut file_tree: Vec<(String, Vec<&str>)> = Vec::new(); + for file in files.clone() { + let mut file_path = file.split('/').collect::>(); + let name = match file_path.pop() { + Some(name) => name, + None => continue, + }; + let file_path = file_path.join("/"); + let mut file_tree_index_found = false; + for (file_tree_index, file_tree_path) in file_tree.iter().enumerate() { + if (file_tree_path).0 == file_path { + file_tree_index_found = true; + file_tree[file_tree_index].1.push(name); + break; + } + } + if !file_tree_index_found { + file_tree.push((file_path, vec![name])); + } + } + + #[cfg(feature = "parallel")] + let t = file_tree.par_iter(); + #[cfg(not(feature = "parallel"))] + let t = file_tree.iter(); + let stuffs = t + .filter_map(|(path, files)| { + let mut file_types = Vec::new(); + for file in files { + let file_path = format!("{}/{}", path, file); + let file_contents = find_file_in_commit(commit, &file_path).ok()?; + + file_types.push((file_path, file_contents)); + } + + match find_function_in_files_with_commit(file_types, name.to_string(), langs) { + vec if !vec.is_empty() => Some(vec), + _ => None, + } + }) + .flat_map(|x| x) + .collect::>(); + if stuffs.is_empty() { Err(err)?; } - Ok(returns) + Ok(stuffs) } - -// #[cached] -// #[cached(result = true)] fn find_function_in_file_with_commit( - commit: &str, file_path: &str, + fc: &str, name: &str, langs: Language, ) -> Result> { - let fc = find_file_in_commit(commit, file_path)?; - // if let Some(file) = MEMOIZE.lock()?.get(&fc) { - // return Ok(file.clone()); + // unsafe { + // file_count += 1; // } let file = match langs { Language::Rust => { - let functions = rust::find_function_in_file(&fc, name)?; - FileType::Rust(RustFile::new( - file_path.to_string(), - functions, - )) + let functions = rust::find_function_in_file(fc, name)?; + FileType::Rust(RustFile::new(file_path.to_string(), functions)) } #[cfg(feature = "c_lang")] Language::C => { - let functions = languages::c::find_function_in_file(&fc, name)?; + let functions = languages::c::find_function_in_file(fc, name)?; FileType::C(CFile::new(file_path.to_string(), functions)) } #[cfg(feature = "unstable")] Language::Go => { - let functions = languages::go::find_function_in_file(&fc, name)?; + let functions = languages::go::find_function_in_file(fc, name)?; FileType::Go(GoFile::new(file_path.to_string(), functions)) } Language::Python => { - let functions = languages::python::find_function_in_file(&fc, name)?; - FileType::Python(PythonFile::new( - file_path.to_string(), - functions, - )) + let functions = languages::python::find_function_in_file(fc, name)?; + FileType::Python(PythonFile::new(file_path.to_string(), functions)) } Language::Ruby => { - let functions = languages::ruby::find_function_in_file(&fc, name)?; - FileType::Ruby(RubyFile::new( - file_path.to_string(), - functions, - )) + let functions = languages::ruby::find_function_in_file(fc, name)?; + FileType::Ruby(RubyFile::new(file_path.to_string(), functions)) } Language::All => match file_path.split('.').last() { Some("rs") => { - let functions = rust::find_function_in_file(&fc, name)?; - FileType::Rust(RustFile::new( - file_path.to_string(), - functions, - )) + let functions = rust::find_function_in_file(fc, name)?; + FileType::Rust(RustFile::new(file_path.to_string(), functions)) } #[cfg(feature = "c_lang")] Some("c" | "h") => { - let functions = languages::c::find_function_in_file(&fc, name)?; + let functions = languages::c::find_function_in_file(fc, name)?; FileType::C(CFile::new(file_path.to_string(), functions)) } Some("py") => { - let functions = languages::python::find_function_in_file(&fc, name)?; - FileType::Python(PythonFile::new( - file_path.to_string(), - functions, - )) + let functions = languages::python::find_function_in_file(fc, name)?; + FileType::Python(PythonFile::new(file_path.to_string(), functions)) } #[cfg(feature = "unstable")] Some("go") => { - let functions = languages::go::find_function_in_file(&fc, name)?; + let functions = languages::go::find_function_in_file(fc, name)?; FileType::Go(GoFile::new(file_path.to_string(), functions)) } Some("rb") => { - let functions = languages::ruby::find_function_in_file(&fc, name)?; - FileType::Ruby(RubyFile::new( - file_path.to_string(), - functions, - )) + let functions = languages::ruby::find_function_in_file(fc, name)?; + FileType::Ruby(RubyFile::new(file_path.to_string(), functions)) } _ => Err("unknown file type")?, }, }; - // MEMOIZE.lock()?.insert(fc, file.clone()); Ok(file) } +#[cfg_attr(feature = "cache", cached)] +// function that takes a vec of files paths and there contents and a function name and uses find_function_in_file_with_commit to find the function in each file and returns a vec of the functions +fn find_function_in_files_with_commit( + files: Vec<(String, String)>, + name: String, + langs: Language, +) -> Vec { + #[cfg(feature = "parallel")] + let t = files.par_iter(); + #[cfg(not(feature = "parallel"))] + let t = files.iter(); + t.filter_map(|(file_path, fc)| { + find_function_in_file_with_commit(file_path, fc, &name, langs).ok() + }) + .collect() +} + trait UnwrapToError { fn unwrap_to_error_sync(self, message: &str) -> Result>; fn unwrap_to_error(self, message: &str) -> Result>; @@ -677,6 +703,9 @@ mod tests { ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); + // unsafe { + // println!("# of files parsed: {}", file_count); + // } match &output { Ok(functions) => { println!("{}", functions); @@ -834,9 +863,7 @@ mod tests { } let f3 = filter_by!( repo, - LanguageFilter::Rust(RustFilter::InBlock( - crate::languages::rust::BlockType::Impl - )), + LanguageFilter::Rust(RustFilter::InBlock(crate::languages::rust::BlockType::Impl)), 1 ); match f3 { From ddb7456ea651c62e1195de55989bbfed9b51d432 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 2 Nov 2022 18:27:43 -0400 Subject: [PATCH 098/172] removing c support (for now) --- cargo-function-history/Cargo.toml | 2 +- function_history_backend_thread/Cargo.toml | 2 +- git-function-history-gui/Cargo.toml | 2 +- git-function-history-lib/Cargo.toml | 4 +- git-function-history-lib/README.md | 7 +- git-function-history-lib/src/languages/mod.rs | 36 ++++---- git-function-history-lib/src/lib.rs | 90 +++++++++---------- git-function-history-lib/src/types.rs | 34 +++---- 8 files changed, 90 insertions(+), 87 deletions(-) diff --git a/cargo-function-history/Cargo.toml b/cargo-function-history/Cargo.toml index 23f611e4..f44647c0 100644 --- a/cargo-function-history/Cargo.toml +++ b/cargo-function-history/Cargo.toml @@ -14,7 +14,7 @@ description = "cargo frontend for git-function-history" default = ["parallel"] parallel = ["git_function_history/parallel", "function_history_backend_thread/parallel"] not-parallel = [] -c_lang = ["function_history_backend_thread/c_lang", "git_function_history/c_lang"] +# c_lang = ["function_history_backend_thread/c_lang", "git_function_history/c_lang"] unstable = ["function_history_backend_thread/unstable", "git_function_history/unstable"] [dependencies] diff --git a/function_history_backend_thread/Cargo.toml b/function_history_backend_thread/Cargo.toml index 141024d1..392496e1 100644 --- a/function_history_backend_thread/Cargo.toml +++ b/function_history_backend_thread/Cargo.toml @@ -15,7 +15,7 @@ description = "threading and types for git-function-history" default = ["parallel"] parallel = ["git_function_history/parallel"] not-parallel = [] -c_lang = ["git_function_history/c_lang"] +# c_lang = ["git_function_history/c_lang"] unstable = ["git_function_history/unstable"] [dependencies] diff --git a/git-function-history-gui/Cargo.toml b/git-function-history-gui/Cargo.toml index 926e38f2..82b482ea 100644 --- a/git-function-history-gui/Cargo.toml +++ b/git-function-history-gui/Cargo.toml @@ -14,7 +14,7 @@ description = "GUI frontend for git-function-history" default = ["parallel"] parallel = ["git_function_history/parallel", "function_history_backend_thread/parallel"] not-parallel = [] -c_lang = ["git_function_history/c_lang", "function_history_backend_thread/c_lang"] +# c_lang = ["git_function_history/c_lang", "function_history_backend_thread/c_lang"] unstable = ["git_function_history/unstable", "function_history_backend_thread/unstable"] [dependencies] diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 5873db5d..f4dc952c 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -9,11 +9,9 @@ categories = ["tools", "git"] description = "show function history from git" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -# default = ["parallel", "unstable", "cache"] -# default = ["parallel", "unstable"] default = ["parallel"] parallel = ["dep:rayon"] -c_lang = [] +# c_lang = [] unstable = ["dep:gosyn", "dep:javaparser"] cache = ["dep:cached"] diff --git a/git-function-history-lib/README.md b/git-function-history-lib/README.md index 8105ff7f..929845d8 100644 --- a/git-function-history-lib/README.md +++ b/git-function-history-lib/README.md @@ -10,10 +10,15 @@ Use the latest [crates.io](https://crates.io/crates/git_function_history) by put ## features - parallel: use rayon to parallelize the git log search + - --no-default-features: disable parallelism -- c-lang: adds support c (requires you to have a c compiler installed) (see the [c-lib]() docs for more information) + + + - unstable: enable some parsers that require nightly rust so run `cargo +nightly` to use them +- cache: enables caching when parsing files that don't change + ## known issues - python: since the parser only finds the beginning of the function we have to use some workarounds to find the end of the function. This means that if you have a function that anything from the end of one function to either the beginning of another function or the end of the file that is not python code for example a comment it will be included in the function. diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index c99c415f..4b0164ff 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -7,8 +7,8 @@ use std::{ // TODO: make a macro for generating filters use self::{python::PythonFunction, ruby::RubyFunction, rust::RustFunction}; -#[cfg(feature = "c_lang")] -use self::c::CFunction; +// #[cfg(feature = "c_lang")] +// use self::c::CFunction; #[cfg(feature = "unstable")] use go::GoFunction; @@ -18,9 +18,9 @@ pub enum Language { Python, /// The rust language Rust, - #[cfg(feature = "c_lang")] - /// c language - C, + // #[cfg(feature = "c_lang")] + // /// c language + // C, #[cfg(feature = "unstable")] /// The go language Go, @@ -35,9 +35,9 @@ pub enum LanguageFilter { Python(python::PythonFilter), /// rust filter Rust(rust::RustFilter), - #[cfg(feature = "c_lang")] - /// c filter - C(c::CFilter), + // #[cfg(feature = "c_lang")] + // /// c filter + // C(c::CFilter), #[cfg(feature = "unstable")] /// go filter Go(go::GoFilter), @@ -50,8 +50,8 @@ impl Language { match s { "python" => Ok(Self::Python), "rust" => Ok(Self::Rust), - #[cfg(feature = "c_lang")] - "c" => Ok(Self::C), + // #[cfg(feature = "c_lang")] + // "c" => Ok(Self::C), #[cfg(feature = "unstable")] "go" => Ok(Self::Go), "all" => Ok(Self::All), @@ -66,8 +66,8 @@ impl fmt::Display for Language { match self { Self::Python => write!(f, "python"), Self::Rust => write!(f, "rust"), - #[cfg(feature = "c_lang")] - Self::C => write!(f, "c"), + // #[cfg(feature = "c_lang")] + // Self::C => write!(f, "c"), #[cfg(feature = "unstable")] Self::Go => write!(f, "go"), Self::Ruby => write!(f, "ruby"), @@ -75,8 +75,8 @@ impl fmt::Display for Language { } } } -#[cfg(feature = "c_lang")] -pub mod c; +// #[cfg(feature = "c_lang")] +// pub mod c; #[cfg(feature = "unstable")] pub mod go; // #[cfg(feature = "unstable")] @@ -256,8 +256,8 @@ macro_rules! make_file { make_file!(PythonFile, PythonFunction, Python); make_file!(RustFile, RustFunction, Rust); -#[cfg(feature = "c_lang")] -make_file!(CFile, CFunction, C); +// #[cfg(feature = "c_lang")] +// make_file!(CFile, CFunction, C); #[cfg(feature = "unstable")] make_file!(GoFile, GoFunction, Go); make_file!(RubyFile, RubyFunction, Ruby); @@ -296,8 +296,8 @@ mod lang_tests { use super::*; make_file_time_test!(python_parses, py, python); make_file_time_test!(rust_parses, rs, rust); - #[cfg(feature = "c_lang")] - make_file_time_test!(c_parses, c, c); + // #[cfg(feature = "c_lang")] + // make_file_time_test!(c_parses, c, c); #[cfg(feature = "unstable")] make_file_time_test!(go_parses, go, go); make_file_time_test!(ruby_parses, rb, ruby); diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index b110eb3f..3aa598c1 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -27,8 +27,8 @@ use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use std::{error::Error, process::Command}; -#[cfg(feature = "c_lang")] -use languages::CFile; +// #[cfg(feature = "c_lang")] +// use languages::CFile; #[cfg(feature = "unstable")] use languages::GoFile; @@ -193,12 +193,12 @@ pub fn get_function_history( // check if file is a rust file if let FileFilterType::Absolute(path) | FileFilterType::Relative(path) = &file { match langs { - #[cfg(feature = "c_lang")] - Language::C => { - if !path.ends_with(".c") && !path.ends_with(".h") { - Err(format!("file is not a c file: {}", path))?; - } - } + // #[cfg(feature = "c_lang")] + // Language::C => { + // if !path.ends_with(".c") && !path.ends_with(".h") { + // Err(format!("file is not a c file: {}", path))?; + // } + // } #[cfg(feature = "unstable")] Language::Go => { if !path.ends_with(".go") { @@ -394,12 +394,12 @@ fn find_function_in_commit_with_filetype( } } FileFilterType::None => match langs { - #[cfg(feature = "c_lang")] - Language::C => { - if file.ends_with(".c") || file.ends_with(".h") { - files.push(file); - } - } + // #[cfg(feature = "c_lang")] + // Language::C => { + // if file.ends_with(".c") || file.ends_with(".h") { + // files.push(file); + // } + // } #[cfg(feature = "unstable")] Language::Go => { if file.ends_with(".go") { @@ -519,11 +519,11 @@ fn find_function_in_file_with_commit( let functions = rust::find_function_in_file(fc, name)?; FileType::Rust(RustFile::new(file_path.to_string(), functions)) } - #[cfg(feature = "c_lang")] - Language::C => { - let functions = languages::c::find_function_in_file(fc, name)?; - FileType::C(CFile::new(file_path.to_string(), functions)) - } + // #[cfg(feature = "c_lang")] + // Language::C => { + // let functions = languages::c::find_function_in_file(fc, name)?; + // FileType::C(CFile::new(file_path.to_string(), functions)) + // } #[cfg(feature = "unstable")] Language::Go => { let functions = languages::go::find_function_in_file(fc, name)?; @@ -542,11 +542,11 @@ fn find_function_in_file_with_commit( let functions = rust::find_function_in_file(fc, name)?; FileType::Rust(RustFile::new(file_path.to_string(), functions)) } - #[cfg(feature = "c_lang")] - Some("c" | "h") => { - let functions = languages::c::find_function_in_file(fc, name)?; - FileType::C(CFile::new(file_path.to_string(), functions)) - } + // #[cfg(feature = "c_lang")] + // Some("c" | "h") => { + // let functions = languages::c::find_function_in_file(fc, name)?; + // FileType::C(CFile::new(file_path.to_string(), functions)) + // } Some("py") => { let functions = languages::python::find_function_in_file(fc, name)?; FileType::Python(PythonFile::new(file_path.to_string(), functions)) @@ -745,27 +745,27 @@ mod tests { let _functions = file.get_functions(); } - #[test] - #[cfg(feature = "c_lang")] - fn c_lang() { - let now = Utc::now(); - let output = get_function_history( - "empty_test", - &FileFilterType::Relative("src/test_functions.c".to_string()), - &Filter::DateRange( - "03 Oct 2022 11:27:23 -0400".to_owned(), - "05 Oct 2022 23:45:52 +0000".to_owned(), - ), - &languages::Language::C, - ); - let after = Utc::now() - now; - println!("time taken: {}", after.num_seconds()); - match &output { - Ok(functions) => println!("{}", functions), - Err(e) => println!("{}", e), - } - assert!(output.is_ok()); - } + // #[test] + // #[cfg(feature = "c_lang")] + // fn c_lang() { + // let now = Utc::now(); + // let output = get_function_history( + // "empty_test", + // &FileFilterType::Relative("src/test_functions.c".to_string()), + // &Filter::DateRange( + // "03 Oct 2022 11:27:23 -0400".to_owned(), + // "05 Oct 2022 23:45:52 +0000".to_owned(), + // ), + // &languages::Language::C, + // ); + // let after = Utc::now() - now; + // println!("time taken: {}", after.num_seconds()); + // match &output { + // Ok(functions) => println!("{}", functions), + // Err(e) => println!("{}", e), + // } + // assert!(output.is_ok()); + // } #[test] fn parse_commit() { diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index a0dd32d8..13227db3 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -13,8 +13,8 @@ use crate::{ Filter, }; -#[cfg(feature = "c_lang")] -use crate::languages::CFile; +// #[cfg(feature = "c_lang")] +// use crate::languages::CFile; #[cfg(feature = "unstable")] use crate::languages::GoFile; @@ -23,8 +23,8 @@ use crate::languages::GoFile; pub enum FileType { Rust(RustFile), Python(PythonFile), - #[cfg(feature = "c_lang")] - C(CFile), + // #[cfg(feature = "c_lang")] + // C(CFile), #[cfg(feature = "unstable")] Go(GoFile), Ruby(RubyFile), @@ -35,8 +35,8 @@ impl FileTrait for FileType { match self { Self::Rust(file) => file.get_file_name(), Self::Python(file) => file.get_file_name(), - #[cfg(feature = "c_lang")] - Self::C(file) => file.get_file_name(), + // #[cfg(feature = "c_lang")] + // Self::C(file) => file.get_file_name(), #[cfg(feature = "unstable")] Self::Go(file) => file.get_file_name(), Self::Ruby(file) => file.get_file_name(), @@ -46,8 +46,8 @@ impl FileTrait for FileType { match self { Self::Rust(file) => file.get_functions(), Self::Python(file) => file.get_functions(), - #[cfg(feature = "c_lang")] - Self::C(file) => file.get_functions(), + // #[cfg(feature = "c_lang")] + // Self::C(file) => file.get_functions(), #[cfg(feature = "unstable")] Self::Go(file) => file.get_functions(), Self::Ruby(file) => file.get_functions(), @@ -64,11 +64,11 @@ impl FileTrait for FileType { let filtered = file.filter_by(filter)?; Ok(Self::Python(filtered)) } - #[cfg(feature = "c_lang")] - Self::C(file) => { - let filtered = file.filter_by(filter)?; - Ok(Self::C(filtered)) - } + // #[cfg(feature = "c_lang")] + // Self::C(file) => { + // let filtered = file.filter_by(filter)?; + // Ok(Self::C(filtered)) + // } #[cfg(feature = "unstable")] Self::Go(file) => { let filtered = file.filter_by(filter)?; @@ -85,8 +85,8 @@ impl FileTrait for FileType { match self { Self::Rust(file) => file.get_current(), Self::Python(file) => file.get_current(), - #[cfg(feature = "c_lang")] - Self::C(file) => file.get_current(), + // #[cfg(feature = "c_lang")] + // Self::C(file) => file.get_current(), #[cfg(feature = "unstable")] Self::Go(file) => file.get_current(), Self::Ruby(file) => file.get_current(), @@ -99,8 +99,8 @@ impl fmt::Display for FileType { match self { Self::Rust(file) => write!(f, "{}", file), Self::Python(file) => write!(f, "{}", file), - #[cfg(feature = "c_lang")] - Self::C(file) => write!(f, "{}", file), + // #[cfg(feature = "c_lang")] + // Self::C(file) => write!(f, "{}", file), #[cfg(feature = "unstable")] Self::Go(file) => write!(f, "{}", file), Self::Ruby(file) => write!(f, "{}", file), From 9e634e7ec936c7829e6aa71393cb1c0c9df5258a Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 2 Nov 2022 19:00:59 -0400 Subject: [PATCH 099/172] pushing towards release --- TODO.md | 8 +++++++ cargo-function-history/src/app/mod.rs | 23 ++++++++++--------- git-function-history-lib/src/languages/c.rs | 5 +--- git-function-history-lib/src/languages/go.rs | 5 +--- .../src/languages/java.rs | 5 +--- git-function-history-lib/src/languages/mod.rs | 7 +++--- .../src/languages/python.rs | 5 +--- .../src/languages/ruby.rs | 5 +--- .../src/languages/rust.rs | 5 +--- 9 files changed, 30 insertions(+), 38 deletions(-) diff --git a/TODO.md b/TODO.md index 07937bf5..12d00b00 100644 --- a/TODO.md +++ b/TODO.md @@ -26,3 +26,11 @@ - [/] add support for other languages (currently only supports rust) - [x] save search queries and filters to a file - [ ] rework the way filters and filefilters are handled ie maybe use a builder pattern + +- release 7.0: + - python: + - [ ] save parent function and classes + - [ ] save kwargs and varargs etc using the args enum and be able to filter by all args or just kwargs etc + - ruby: + - [ ] save kwargs and varargs etc using the args enum and be able to filter by all args or just kwargs etc + diff --git a/cargo-function-history/src/app/mod.rs b/cargo-function-history/src/app/mod.rs index 7ce9cc55..e458d75f 100644 --- a/cargo-function-history/src/app/mod.rs +++ b/cargo-function-history/src/app/mod.rs @@ -176,11 +176,19 @@ impl App { let mut file = FileFilterType::None; let mut filter = Filter::None; let mut lang = Language::All; + let new_vec = iter.collect::>(); + let mut new_iter = new_vec.windows(2); log::debug!( "searching for {:?}", - iter.clone().collect::>().windows(2) + new_iter ); - for i in &mut iter.clone().collect::>().windows(2) { + + if new_vec.len() % 2 != 0 { + self.status = Status::Error(format!("uncomplete search, command: {} doesnt have its parameters",new_vec.last().expect("oops look like theres nothing in this vec don't how this happened").to_string())); + return; + } + for i in &mut new_iter { + log::info!("i: {:?}", i); match i { ["relative", filepath] => { log::trace!("relative file: {}", filepath); @@ -221,8 +229,8 @@ impl App { lang = match language { &"rust" => Language::Rust, &"python" => Language::Python, - #[cfg(feature = "c_lang")] - &"c" => Language::C, + // #[cfg(feature = "c_lang")] + // &"c" => Language::C, #[cfg(feature = "unstable")] &"go" => Language::Go, &"ruby" => Language::Ruby, @@ -253,13 +261,6 @@ impl App { } } } - if iter.clone().count() > 0 { - self.status = Status::Error(format!( - "Invalid search, command: {:?} missing args", - iter.collect::>() - )); - return; - } self.channels .0 .send(FullCommand::Search(name.to_string(), file, filter, lang)) diff --git a/git-function-history-lib/src/languages/c.rs b/git-function-history-lib/src/languages/c.rs index acc821d4..b4a24247 100644 --- a/git-function-history-lib/src/languages/c.rs +++ b/git-function-history-lib/src/languages/c.rs @@ -64,10 +64,7 @@ pub struct ParentFunction { pub(crate) returns: Option, } #[inline] -/* -use cached::proc_macro::cached; -#[cached(result = true)] -*/ + pub(crate) fn find_function_in_file( file_contents: &str, name: &str, diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index 06b25e64..4a1051a6 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -71,10 +71,7 @@ impl FunctionTrait for GoFunction { (start, end) } } -/* -use cached::proc_macro::cached; -#[cached(result = true)] -*/ + pub(crate) fn find_function_in_file( file_contents: &str, name: &str, diff --git a/git-function-history-lib/src/languages/java.rs b/git-function-history-lib/src/languages/java.rs index 1b81aaf7..eb13dde2 100644 --- a/git-function-history-lib/src/languages/java.rs +++ b/git-function-history-lib/src/languages/java.rs @@ -68,10 +68,7 @@ pub enum JavaBlockType { Enum, Interface, } -/* -use cached::proc_macro::cached; -#[cached(result = true)] -*/ + pub(crate) fn find_function_in_file( file_contents: &str, name: &str, diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 4b0164ff..3ba2ff60 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -262,7 +262,10 @@ make_file!(RustFile, RustFunction, Rust); make_file!(GoFile, GoFunction, Go); make_file!(RubyFile, RubyFunction, Ruby); -// macro that auto genertes the test parse__file_time + +#[cfg(test)] +mod lang_tests { + // macro that auto genertes the test parse__file_time macro_rules! make_file_time_test { ($name:ident, $extname:ident, $function:ident) => { #[test] @@ -291,8 +294,6 @@ macro_rules! make_file_time_test { }; } -#[cfg(test)] -mod lang_tests { use super::*; make_file_time_test!(python_parses, py, python); make_file_time_test!(rust_parses, rs, rust); diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 69060fa2..c40b1b10 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -67,10 +67,7 @@ pub struct PythonParentFunction { // pub(crate) class: Option, pub(crate) returns: Option, } -/* -use cached::proc_macro::cached; -#[cached(result = true)] -*/ + pub(crate) fn find_function_in_file( file_contents: &str, name: &str, diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index c3853bb0..0819fdcf 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -59,10 +59,7 @@ pub struct RubyClass { pub top: String, pub bottom: String, } -/* -use cached::proc_macro::cached; -#[cached(result = true)] -*/ + pub(crate) fn find_function_in_file( file_contents: &str, name: &str, diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index c8d27dc7..b55940a2 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -197,10 +197,7 @@ impl fmt::Display for BlockType { } } } -/* -use cached::proc_macro::cached; -#[cached(result = true)] -*/ + #[allow(clippy::too_many_lines)] // TODO: split this function into smaller functions pub(crate) fn find_function_in_file( From 26131eaf146c15c50651c3999fcb9e0c568991fb Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 3 Nov 2022 15:26:48 -0400 Subject: [PATCH 100/172] ideas comments etc --- TODO.md | 8 +++++++- git-function-history-lib/Cargo.toml | 8 ++++++-- .../src/languages/python.rs | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/TODO.md b/TODO.md index 12d00b00..9b1bbff4 100644 --- a/TODO.md +++ b/TODO.md @@ -33,4 +33,10 @@ - [ ] save kwargs and varargs etc using the args enum and be able to filter by all args or just kwargs etc - ruby: - [ ] save kwargs and varargs etc using the args enum and be able to filter by all args or just kwargs etc - + - gui: + - [ ] make the list of dates clickable so when you click on a date/commit it will automatically run a search for that date/commit + - [ ] make list command a table wiht rows and columns for date, commit, author, message, etc + - [ ] (possibly) use tree sitter to provide syntax highlighting + - tui: + - [ ] make list command a table wiht rows and columns for date, commit, author, message, etc + - [ ] (possibly) use tree sitter to provide syntax highlighting diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index f4dc952c..c689b1f7 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -12,7 +12,8 @@ description = "show function history from git" default = ["parallel"] parallel = ["dep:rayon"] # c_lang = [] -unstable = ["dep:gosyn", "dep:javaparser"] +# unstable = ["dep:gosyn", "dep:javaparser"] +unstable = ["dep:gosyn"] cache = ["dep:cached"] [dependencies] @@ -20,8 +21,11 @@ chrono = "0.4.22" ra_ap_syntax = "0.0.137" rayon = { version = "1.5.3", optional = true } rustpython-parser = "0.1.2" +# for end_lines but can't be publsihed b/c git depenency +# rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "77b821a1941019fe34f73ce17cea013ae1b98fd0" } lib-ruby-parser = "3.0.12" gosyn = {version = "0.1.1", optional = true} -javaparser = {git = "https://github.com/tanin47/javaparser.rs", optional = true} +# can't be published b/c git dependency +# javaparser = {git = "https://github.com/tanin47/javaparser.rs", optional = true} cfg-if = "1.0.0" cached = {version = "0.40.0", optional = true} \ No newline at end of file diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index c40b1b10..98e05747 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -9,6 +9,22 @@ use std::{collections::HashMap, fmt}; use crate::{impl_function_trait, UnwrapToError}; use super::FunctionTrait; +// #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] +// pub struct Range { +// pub location: Location, +// pub end_location: Location, +// } + +// impl Range { +// pub fn from_located(located: &Located) -> Self { +// Range { +// location: located.location, +// end_location: located +// .end_location +// .expect("AST nodes should have end_location."), +// } +// } +// } #[derive(Debug, Clone)] pub struct PythonFunction { @@ -220,6 +236,8 @@ fn get_functions<'a>( } else { *last_found_fn = Some((stmt.node, stmt.location)); } + // let r = Range::from_located(&stmt); + // println!("Found function {} at {:?}", name, r); } StatementType::If { body, orelse, .. } From 359068374f03a84cef416036f00cfcf6bf8b87b6 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Fri, 4 Nov 2022 14:13:05 -0400 Subject: [PATCH 101/172] gui: started working on clickable dates/commits using list also clippied/formattede stuff --- cargo-function-history/src/app/mod.rs | 7 +- git-function-history-gui/src/lib.rs | 936 ++++++++++-------- git-function-history-lib/src/languages/go.rs | 4 +- git-function-history-lib/src/languages/mod.rs | 59 +- .../src/languages/python.rs | 2 +- .../src/languages/ruby.rs | 4 +- .../src/languages/rust.rs | 6 +- git-function-history-lib/src/lib.rs | 56 +- git-function-history-lib/src/types.rs | 8 +- 9 files changed, 576 insertions(+), 506 deletions(-) diff --git a/cargo-function-history/src/app/mod.rs b/cargo-function-history/src/app/mod.rs index e458d75f..6de0feae 100644 --- a/cargo-function-history/src/app/mod.rs +++ b/cargo-function-history/src/app/mod.rs @@ -178,13 +178,10 @@ impl App { let mut lang = Language::All; let new_vec = iter.collect::>(); let mut new_iter = new_vec.windows(2); - log::debug!( - "searching for {:?}", - new_iter - ); + log::debug!("searching for {:?}", new_iter); if new_vec.len() % 2 != 0 { - self.status = Status::Error(format!("uncomplete search, command: {} doesnt have its parameters",new_vec.last().expect("oops look like theres nothing in this vec don't how this happened").to_string())); + self.status = Status::Error(format!("uncomplete search, command: {} doesnt have its parameters",new_vec.last().expect("oops look like theres nothing in this vec don't how this happened"))); return; } for i in &mut new_iter { diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index 32584f34..1d96ed9b 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -28,6 +28,8 @@ pub struct MyEguiApp { file_type: FileFilterType, history_filter_type: HistoryFilterType, language: Language, + current_commit: String, + do_commit: bool, } impl MyEguiApp { @@ -50,9 +52,21 @@ impl MyEguiApp { filter: Filter::None, history_filter_type: HistoryFilterType::None, language: Language::All, + current_commit: String::new(), + do_commit: false, } } + fn draw_config_window(&mut self, ctx: &egui::Context) { + egui::Window::new("My Window") + .open(&mut true) + .show(ctx, |ui| { + if ui.button("cancel").clicked() { + self.current_commit = String::new(); + } + }); + } + fn draw_commit(commit: &mut Commit, ctx: &egui::Context, show: bool) { if show { TopBottomPanel::top("date_id").show(ctx, |ui| { @@ -233,314 +247,344 @@ impl eframe::App for MyEguiApp { } else { ctx.set_visuals(Visuals::light()); } - egui::TopBottomPanel::bottom("status_bar").show(ctx, |ui| { - ui.add_space(20.); - egui::menu::bar(ui, |ui| { - ui.with_layout( - Layout::left_to_right(eframe::emath::Align::Center), - |ui| match &self.status { - Status::Loading => { - ui.colored_label(Color32::BLUE, "Loading..."); - } - Status::Ok(a) => match a { - Some(a) => { - ui.colored_label(Color32::LIGHT_GREEN, format!("Ok: {}", a)); + if self.do_commit { + self.draw_config_window(ctx); + if self.current_commit.is_empty() { + self.do_commit = false; + } + } else { + egui::TopBottomPanel::bottom("status_bar").show(ctx, |ui| { + ui.add_space(20.); + egui::menu::bar(ui, |ui| { + ui.with_layout(Layout::left_to_right(eframe::emath::Align::Center), |ui| { + match &self.status { + Status::Loading => { + ui.colored_label(Color32::BLUE, "Loading..."); } - None => { - ui.colored_label(Color32::GREEN, "Ready"); + Status::Ok(a) => match a { + Some(a) => { + ui.colored_label(Color32::LIGHT_GREEN, format!("Ok: {}", a)); + } + None => { + ui.colored_label(Color32::GREEN, "Ready"); + } + }, + Status::Warning(a) => { + ui.colored_label(Color32::LIGHT_RED, format!("Warn: {}", a)); + } + Status::Error(a) => { + ui.colored_label(Color32::LIGHT_RED, format!("Error: {}", a)); } - }, - Status::Warning(a) => { - ui.colored_label(Color32::LIGHT_RED, format!("Warn: {}", a)); - } - Status::Error(a) => { - ui.colored_label(Color32::LIGHT_RED, format!("Error: {}", a)); } - }, - ); - // controls - ui.with_layout(Layout::right_to_left(eframe::emath::Align::Center), |ui| { - let theme_btn = ui.add(Button::new({ - if self.dark_theme { - "🌞" - } else { - "🌙" + }); + // controls + ui.with_layout(Layout::right_to_left(eframe::emath::Align::Center), |ui| { + let theme_btn = ui.add(Button::new({ + if self.dark_theme { + "🌞" + } else { + "🌙" + } + })); + if theme_btn.clicked() { + self.dark_theme = !self.dark_theme; } - })); - if theme_btn.clicked() { - self.dark_theme = !self.dark_theme; - } + }); }); - }); - ui.add_space(20.); - }); - egui::TopBottomPanel::bottom("commnad_builder").show(ctx, |ui| { - egui::menu::bar(ui, |ui| { - egui::ScrollArea::horizontal() - .max_height(f32::INFINITY) - .max_width(f32::INFINITY) - .auto_shrink([false, false]) - .show(ui, |ui| { - let max = ui.available_width() / 6.0; - egui::ComboBox::from_id_source("command_combo_box") - .selected_text(self.command.to_string()) - .show_ui(ui, |ui| { - ui.selectable_value(&mut self.command, Command::Filter, "filter"); - ui.selectable_value(&mut self.command, Command::Search, "search"); - ui.selectable_value(&mut self.command, Command::List, "list"); - }); - match self.command { - Command::Filter => { - match &self.cmd_output { - CommandResult::History(_) => { - // Options 1. by date 2. by commit hash 3. in date range 4. function in block 5. function in lines 6. function in function - let text = match &self.history_filter_type { - HistoryFilterType::None => "filter type".to_string(), - a => a.to_string(), - }; - egui::ComboBox::from_id_source("history_combo_box") - .selected_text(text) - .show_ui(ui, |ui| { - ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::Date(String::new()), - "by date", - ); - ui.selectable_value( + ui.add_space(20.); + }); + egui::TopBottomPanel::bottom("commnad_builder").show(ctx, |ui| { + egui::menu::bar(ui, |ui| { + egui::ScrollArea::horizontal() + .max_height(f32::INFINITY) + .max_width(f32::INFINITY) + .auto_shrink([false, false]) + .show(ui, |ui| { + let max = ui.available_width() / 6.0; + egui::ComboBox::from_id_source("command_combo_box") + .selected_text(self.command.to_string()) + .show_ui(ui, |ui| { + ui.selectable_value( + &mut self.command, + Command::Filter, + "filter", + ); + ui.selectable_value( + &mut self.command, + Command::Search, + "search", + ); + ui.selectable_value(&mut self.command, Command::List, "list"); + }); + match self.command { + Command::Filter => { + match &self.cmd_output { + CommandResult::History(_) => { + // Options 1. by date 2. by commit hash 3. in date range 4. function in block 5. function in lines 6. function in function + let text = match &self.history_filter_type { + HistoryFilterType::None => { + "filter type".to_string() + } + a => a.to_string(), + }; + egui::ComboBox::from_id_source("history_combo_box") + .selected_text(text) + .show_ui(ui, |ui| { + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::Date(String::new()), + "by date", + ); + ui.selectable_value( &mut self.history_filter_type, HistoryFilterType::CommitHash(String::new()), "by commit hash", ); - ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::DateRange( - String::new(), - String::new(), - ), - "in date range", - ); - ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::FunctionInBlock( - String::new(), - ), - "function in block", - ); - ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::FunctionInLines( - String::new(), - String::new(), - ), - "function in lines", - ); - ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::FunctionInFunction( - String::new(), - ), - "function in function", - ); - ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::FileAbsolute(String::new()), - "file absolute", - ); - ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::FileRelative(String::new()), - "file relative", - ); - ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::Directory(String::new()), - "directory", - ); - ui.selectable_value( - &mut self.history_filter_type, - HistoryFilterType::None, - "none", - ); - }); - match &mut self.history_filter_type { - HistoryFilterType::DateRange(line1, line2) - | HistoryFilterType::FunctionInLines(line1, line2) => { - ui.horizontal(|ui| { - // set the width of the input field - ui.set_min_width(4.0); - ui.set_max_width(max); - ui.add(TextEdit::singleline(line1)); - }); - ui.horizontal(|ui| { - // set the width of the input field - ui.set_min_width(4.0); - ui.set_max_width(max); - ui.add(TextEdit::singleline(line2)); - }); - } - HistoryFilterType::Date(dir) - | HistoryFilterType::CommitHash(dir) - | HistoryFilterType::FunctionInBlock(dir) - | HistoryFilterType::FunctionInFunction(dir) - | HistoryFilterType::FileAbsolute(dir) - | HistoryFilterType::FileRelative(dir) - | HistoryFilterType::Directory(dir) => { - ui.horizontal(|ui| { - // set the width of the input field - ui.set_min_width(4.0); - ui.set_max_width(max); - ui.add(TextEdit::singleline(dir)); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::DateRange( + String::new(), + String::new(), + ), + "in date range", + ); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::FunctionInBlock( + String::new(), + ), + "function in block", + ); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::FunctionInLines( + String::new(), + String::new(), + ), + "function in lines", + ); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::FunctionInFunction( + String::new(), + ), + "function in function", + ); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::FileAbsolute( + String::new(), + ), + "file absolute", + ); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::FileRelative( + String::new(), + ), + "file relative", + ); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::Directory(String::new()), + "directory", + ); + ui.selectable_value( + &mut self.history_filter_type, + HistoryFilterType::None, + "none", + ); }); - } - HistoryFilterType::None => { - // do nothing - } - } - let resp = ui.add(Button::new("Go")); - if resp.clicked() { - self.status = Status::Loading; - let filter = match &self.history_filter_type { - HistoryFilterType::Date(date) => { - Some(Filter::Date(date.to_string())) - } - HistoryFilterType::CommitHash(commit_hash) => Some( - Filter::CommitHash(commit_hash.to_string()), - ), - HistoryFilterType::DateRange(date1, date2) => { - Some(Filter::DateRange( - date1.to_string(), - date2.to_string(), - )) - } - HistoryFilterType::FunctionInBlock(_block) => None, - // Some( - // Filter::FunctionInBlock(BlockType::from_string(block)), - // ), - HistoryFilterType::FunctionInLines( + match &mut self.history_filter_type { + HistoryFilterType::DateRange(line1, line2) + | HistoryFilterType::FunctionInLines( line1, line2, ) => { - let fn_in_lines = ( - match line1.parse::() { - Ok(x) => x, - Err(e) => { - self.status = - Status::Error(format!("{}", e)); - return; - } - }, - match line2.parse::() { - Ok(x) => x, - Err(e) => { - self.status = - Status::Error(format!("{}", e)); - return; - } - }, - ); - Some(Filter::FunctionInLines( - fn_in_lines.0, - fn_in_lines.1, - )) - } - HistoryFilterType::FunctionInFunction( - _function, - ) => { - // Some(Filter::FunctionWithParent(function.to_string())) - None - } - HistoryFilterType::FileAbsolute(file) => { - Some(Filter::FileAbsolute(file.to_string())) - } - HistoryFilterType::FileRelative(file) => { - Some(Filter::FileRelative(file.to_string())) + ui.horizontal(|ui| { + // set the width of the input field + ui.set_min_width(4.0); + ui.set_max_width(max); + ui.add(TextEdit::singleline(line1)); + }); + ui.horizontal(|ui| { + // set the width of the input field + ui.set_min_width(4.0); + ui.set_max_width(max); + ui.add(TextEdit::singleline(line2)); + }); } - HistoryFilterType::Directory(dir) => { - Some(Filter::Directory(dir.to_string())) + HistoryFilterType::Date(dir) + | HistoryFilterType::CommitHash(dir) + | HistoryFilterType::FunctionInBlock(dir) + | HistoryFilterType::FunctionInFunction(dir) + | HistoryFilterType::FileAbsolute(dir) + | HistoryFilterType::FileRelative(dir) + | HistoryFilterType::Directory(dir) => { + ui.horizontal(|ui| { + // set the width of the input field + ui.set_min_width(4.0); + ui.set_max_width(max); + ui.add(TextEdit::singleline(dir)); + }); } HistoryFilterType::None => { - self.status = Status::Ok(None); - None + // do nothing + } + } + let resp = ui.add(Button::new("Go")); + if resp.clicked() { + self.status = Status::Loading; + let filter = match &self.history_filter_type { + HistoryFilterType::Date(date) => { + Some(Filter::Date(date.to_string())) + } + HistoryFilterType::CommitHash(commit_hash) => { + Some(Filter::CommitHash( + commit_hash.to_string(), + )) + } + HistoryFilterType::DateRange(date1, date2) => { + Some(Filter::DateRange( + date1.to_string(), + date2.to_string(), + )) + } + HistoryFilterType::FunctionInBlock(_block) => { + None + } + // Some( + // Filter::FunctionInBlock(BlockType::from_string(block)), + // ), + HistoryFilterType::FunctionInLines( + line1, + line2, + ) => { + let fn_in_lines = ( + match line1.parse::() { + Ok(x) => x, + Err(e) => { + self.status = Status::Error( + format!("{}", e), + ); + return; + } + }, + match line2.parse::() { + Ok(x) => x, + Err(e) => { + self.status = Status::Error( + format!("{}", e), + ); + return; + } + }, + ); + Some(Filter::FunctionInLines( + fn_in_lines.0, + fn_in_lines.1, + )) + } + HistoryFilterType::FunctionInFunction( + _function, + ) => { + // Some(Filter::FunctionWithParent(function.to_string())) + None + } + HistoryFilterType::FileAbsolute(file) => { + Some(Filter::FileAbsolute(file.to_string())) + } + HistoryFilterType::FileRelative(file) => { + Some(Filter::FileRelative(file.to_string())) + } + HistoryFilterType::Directory(dir) => { + Some(Filter::Directory(dir.to_string())) + } + HistoryFilterType::None => { + self.status = Status::Ok(None); + None + } + }; + if let Some(filter) = filter { + self.channels + .0 + .send(FullCommand::Filter(FilterType { + thing: self.cmd_output.clone(), + filter, + })) + .unwrap(); } - }; - if let Some(filter) = filter { - self.channels - .0 - .send(FullCommand::Filter(FilterType { - thing: self.cmd_output.clone(), - filter, - })) - .unwrap(); } } - } - _ => { - ui.add(Label::new("No filters available")); + _ => { + ui.add(Label::new("No filters available")); + } } } - } - Command::Search => { - ui.add(Label::new("Function Name:")); - ui.horizontal(|ui| { - // set the width of the input field - ui.set_min_width(4.0); - ui.set_max_width(max); - ui.add(TextEdit::singleline(&mut self.input_buffer)); - }); - - let text = match &self.file_type { - FileFilterType::Directory(_) => "directory", - FileFilterType::Absolute(_) => "absolute", - FileFilterType::Relative(_) => "relative", - _ => "file type", - }; - egui::ComboBox::from_id_source("search_file_combo_box") - .selected_text(text) - .show_ui(ui, |ui| { - ui.selectable_value( - &mut self.file_type, - FileFilterType::None, - "None", - ); - ui.selectable_value( - &mut self.file_type, - FileFilterType::Relative(String::new()), - "Relative", - ); - ui.selectable_value( - &mut self.file_type, - FileFilterType::Absolute(String::new()), - "Absolute", - ); - ui.selectable_value( - &mut self.file_type, - FileFilterType::Directory(String::new()), - "Directory", - ); + Command::Search => { + ui.add(Label::new("Function Name:")); + ui.horizontal(|ui| { + // set the width of the input field + ui.set_min_width(4.0); + ui.set_max_width(max); + ui.add(TextEdit::singleline(&mut self.input_buffer)); }); - match &mut self.file_type { - FileFilterType::None => {} - FileFilterType::Relative(dir) - | FileFilterType::Absolute(dir) - | FileFilterType::Directory(dir) => { - ui.horizontal(|ui| { - // set the width of the input field - ui.set_min_width(4.0); - ui.set_max_width(max); - ui.add(TextEdit::singleline(dir)); + + let text = match &self.file_type { + FileFilterType::Directory(_) => "directory", + FileFilterType::Absolute(_) => "absolute", + FileFilterType::Relative(_) => "relative", + _ => "file type", + }; + egui::ComboBox::from_id_source("search_file_combo_box") + .selected_text(text) + .show_ui(ui, |ui| { + ui.selectable_value( + &mut self.file_type, + FileFilterType::None, + "None", + ); + ui.selectable_value( + &mut self.file_type, + FileFilterType::Relative(String::new()), + "Relative", + ); + ui.selectable_value( + &mut self.file_type, + FileFilterType::Absolute(String::new()), + "Absolute", + ); + ui.selectable_value( + &mut self.file_type, + FileFilterType::Directory(String::new()), + "Directory", + ); }); + match &mut self.file_type { + FileFilterType::None => {} + FileFilterType::Relative(dir) + | FileFilterType::Absolute(dir) + | FileFilterType::Directory(dir) => { + ui.horizontal(|ui| { + // set the width of the input field + ui.set_min_width(4.0); + ui.set_max_width(max); + ui.add(TextEdit::singleline(dir)); + }); + } } - } - // get filters if any - let text = match &self.filter { - Filter::CommitHash(_) => "commit hash".to_string(), - Filter::DateRange(..) => "date range".to_string(), - Filter::Date(_) => "date".to_string(), - _ => "filter type".to_string(), - }; - egui::ComboBox::from_id_source("search_search_filter_combo_box") + // get filters if any + let text = match &self.filter { + Filter::CommitHash(_) => "commit hash".to_string(), + Filter::DateRange(..) => "date range".to_string(), + Filter::Date(_) => "date".to_string(), + _ => "filter type".to_string(), + }; + egui::ComboBox::from_id_source( + "search_search_filter_combo_box", + ) .selected_text(text) .show_ui(ui, |ui| { ui.selectable_value(&mut self.filter, Filter::None, "None"); @@ -561,166 +605,196 @@ impl eframe::App for MyEguiApp { ); }); - // let - match &mut self.filter { - Filter::None => {} - Filter::CommitHash(thing) | Filter::Date(thing) => { - ui.horizontal(|ui| { - // set the width of the input field - ui.set_min_width(4.0); - ui.set_max_width(max); - ui.add(TextEdit::singleline(thing)); - }); + // let + match &mut self.filter { + Filter::None => {} + Filter::CommitHash(thing) | Filter::Date(thing) => { + ui.horizontal(|ui| { + // set the width of the input field + ui.set_min_width(4.0); + ui.set_max_width(max); + ui.add(TextEdit::singleline(thing)); + }); + } + Filter::DateRange(start, end) => { + ui.horizontal(|ui| { + // set the width of the input field + ui.set_min_width(4.0); + ui.set_max_width(max); + ui.add(TextEdit::singleline(start)); + }); + ui.add(Label::new("-")); + ui.horizontal(|ui| { + // set the width of the input field + ui.set_min_width(4.0); + ui.set_max_width(max); + ui.add(TextEdit::singleline(end)); + }); + } + _ => {} } - Filter::DateRange(start, end) => { - ui.horizontal(|ui| { - // set the width of the input field - ui.set_min_width(4.0); - ui.set_max_width(max); - ui.add(TextEdit::singleline(start)); - }); - ui.add(Label::new("-")); - ui.horizontal(|ui| { - // set the width of the input field - ui.set_min_width(4.0); - ui.set_max_width(max); - ui.add(TextEdit::singleline(end)); + let text = match self.language { + Language::Rust => "Rust", + #[cfg(feature = "c_lang")] + Language::C => "C", + + Language::Python => "Python", + Language::All => "Language", + #[cfg(feature = "unstable")] + Language::Go => "Go", + Language::Ruby => "Ruby", + }; + egui::ComboBox::from_id_source("search_language_combo_box") + .selected_text(text) + .show_ui(ui, |ui| { + ui.selectable_value( + &mut self.language, + Language::Rust, + "Rust", + ); + #[cfg(feature = "c_lang")] + ui.selectable_value( + &mut self.language, + Language::C, + "C", + ); + ui.selectable_value( + &mut self.language, + Language::Python, + "Python", + ); + ui.selectable_value( + &mut self.language, + Language::All, + "All", + ); }); + let resp = ui.add(Button::new("Go")); + if resp.clicked() { + self.status = Status::Loading; + self.channels + .0 + .send(FullCommand::Search( + self.input_buffer.clone(), + self.file_type.clone(), + self.filter.clone(), + Language::Rust, + )) + .unwrap(); } - _ => {} - } - let text = match self.language { - Language::Rust => "Rust", - #[cfg(feature = "c_lang")] - Language::C => "C", - - Language::Python => "Python", - Language::All => "Language", - #[cfg(feature = "unstable")] - Language::Go => "Go", - Language::Ruby => "Ruby", - }; - egui::ComboBox::from_id_source("search_language_combo_box") - .selected_text(text) - .show_ui(ui, |ui| { - ui.selectable_value( - &mut self.language, - Language::Rust, - "Rust", - ); - #[cfg(feature = "c_lang")] - ui.selectable_value(&mut self.language, Language::C, "C"); - ui.selectable_value( - &mut self.language, - Language::Python, - "Python", - ); - ui.selectable_value( - &mut self.language, - Language::All, - "All", - ); - }); - let resp = ui.add(Button::new("Go")); - if resp.clicked() { - self.status = Status::Loading; - self.channels - .0 - .send(FullCommand::Search( - self.input_buffer.clone(), - self.file_type.clone(), - self.filter.clone(), - Language::Rust, - )) - .unwrap(); } - } - Command::List => { - egui::ComboBox::from_id_source("list_type") - .selected_text(self.list_type.to_string()) - .show_ui(ui, |ui| { - ui.selectable_value( - &mut self.list_type, - ListType::Dates, - "dates", - ); - ui.selectable_value( - &mut self.list_type, - ListType::Commits, - "commits", - ); - }); - let resp = ui.add(Button::new("Go")); - if resp.clicked() { - self.status = Status::Loading; - self.channels - .0 - .send(FullCommand::List(self.list_type)) - .unwrap(); + Command::List => { + egui::ComboBox::from_id_source("list_type") + .selected_text(self.list_type.to_string()) + .show_ui(ui, |ui| { + ui.selectable_value( + &mut self.list_type, + ListType::Dates, + "dates", + ); + ui.selectable_value( + &mut self.list_type, + ListType::Commits, + "commits", + ); + }); + let resp = ui.add(Button::new("Go")); + if resp.clicked() { + self.status = Status::Loading; + self.channels + .0 + .send(FullCommand::List(self.list_type)) + .unwrap(); + } } } - } - }); + }); + }); }); - }); - egui::CentralPanel::default().show(ctx, |ui| { - // check if the channel has a message and if so set it to self.command - match self.channels.1.recv_timeout(Duration::from_millis(100)) { - Ok(timeout) => match timeout { - (_, Status::Error(e)) => { - let e = e.split_once("why").unwrap_or((&e, "")); - let e = format!( - "error recieved last command didn't work; {}{}", - e.0, - e.1.split_once("why").unwrap_or(("", "")).0, - ); - log::warn!("{}", e); - self.status = Status::Error(e); - } - (t, Status::Ok(msg)) => { - log::info!("got results of last command"); - self.status = Status::Ok(msg); - self.cmd_output = t; - } - _ => {} - }, - Err(e) => match e { - mpsc::RecvTimeoutError::Timeout => {} - mpsc::RecvTimeoutError::Disconnected => { - panic!("Disconnected"); - } - }, - } - // match self.commmand and render based on that - match &mut self.cmd_output { - CommandResult::History(t) => { - Self::draw_history(t, ctx); + egui::CentralPanel::default().show(ctx, |ui| { + // check if the channel has a message and if so set it to self.command + match self.channels.1.recv_timeout(Duration::from_millis(100)) { + Ok(timeout) => match timeout { + (_, Status::Error(e)) => { + let e = e.split_once("why").unwrap_or((&e, "")); + let e = format!( + "error recieved last command didn't work; {}{}", + e.0, + e.1.split_once("why").unwrap_or(("", "")).0, + ); + log::warn!("{}", e); + self.status = Status::Error(e); + } + (t, Status::Ok(msg)) => { + log::info!("got results of last command"); + self.status = Status::Ok(msg); + self.cmd_output = t; + } + _ => {} + }, + Err(e) => match e { + mpsc::RecvTimeoutError::Timeout => {} + mpsc::RecvTimeoutError::Disconnected => { + panic!("Disconnected"); + } + }, } + // match self.commmand and render based on that + match &mut self.cmd_output { + CommandResult::History(t) => { + Self::draw_history(t, ctx); + } - CommandResult::String(t) => { - egui::ScrollArea::vertical() - .max_height(f32::INFINITY) - .max_width(f32::INFINITY) - .auto_shrink([false, false]) - .show(ui, |ui| { - for line in t { - if !line.is_empty() { - ui.add(Label::new(line.to_string())); + CommandResult::String(t) => { + let resp = ui.button("go"); + egui::ScrollArea::vertical() + .max_height(f32::INFINITY) + .max_width(f32::INFINITY) + .auto_shrink([false, false]) + .show(ui, |ui| { + for line in t { + if !line.is_empty() { + // ui.add(Button::new(line.to_string())); + ui.selectable_value( + &mut self.current_commit, + line.to_string(), + line.to_string(), + ); + } } - } - }); - } - CommandResult::None => match &self.status { - Status::Loading => { - ui.add(Label::new("Loading...")); - } - _ => { - ui.add(Label::new("Nothing to show")); - ui.add(Label::new("Please select a command")); + }); + if resp.clicked() { + // show a popup window + // let response = ui.button("Open popup"); + // let popup_id = ui.make_persistent_id("my_unique_id"); + // // if response.clicked() { + // ui.memory().toggle_popup(popup_id); + // // } + // egui::popup::popup_below_widget(ui, popup_id, &resp, |ui| { + // ui.set_min_width(200.0); // if you want to control the size + // ui.label("Some more info, or things you can select:"); + // ui.label("…"); + // }); + // egui::Area::new("my_area") + // .fixed_pos(egui::pos2(32.0, 32.0)) + // .show(ctx, |ui| { + // ui.label("Floating text!"); + // }); + self.do_commit = true; + } } - }, - }; - }); + CommandResult::None => match &self.status { + Status::Loading => { + ui.add(Label::new("Loading...")); + } + _ => { + ui.add(Label::new("Nothing to show")); + ui.add(Label::new("Please select a command")); + } + }, + }; + }); + } } } diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index 4a1051a6..f1674f28 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -77,7 +77,7 @@ pub(crate) fn find_function_in_file( name: &str, ) -> Result, Box> { let parsed_file = gosyn::parse_source(file_contents) - .map_err(|e| format!("{:?}", e))? + .map_err(|e| format!("{e:?}"))? .decl; let parsed = parsed_file .into_iter() @@ -209,7 +209,7 @@ pub(crate) fn find_function_in_file( }) .collect::>(); if parsed.is_empty() { - return Err(format!("could not find function {} in file", name).into()); + return Err(format!("could not find function {name} in file"))?; } Ok(parsed) } diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 3ba2ff60..b48a76a8 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -56,7 +56,7 @@ impl Language { "go" => Ok(Self::Go), "all" => Ok(Self::All), "ruby" => Ok(Self::Ruby), - _ => Err(format!("Unknown language: {}", s))?, + _ => Err(format!("Unknown language: {s}"))?, } } } @@ -130,26 +130,26 @@ pub fn fmt_with_context( write!(f, "{}", current.get_tops().join("\n"))?; write!(f, "{}", current.get_body())?; } else { - write!(f, "{}", current)?; + write!(f, "{current}")?; } } (Some(prev), None) => { if prev.get_total_lines() == current.get_total_lines() { write!(f, "{}", current.get_body())?; } else { - write!(f, "{}", current)?; + write!(f, "{current}")?; } } (None, Some(next)) => { if next.get_total_lines() == current.get_total_lines() { write!(f, "{}", current.get_body())?; } else { - write!(f, "{}", current)?; + write!(f, "{current}")?; } } (None, None) => { // print the function - write!(f, "{}", current)?; + write!(f, "{current}")?; } } Ok(()) @@ -262,37 +262,36 @@ make_file!(RustFile, RustFunction, Rust); make_file!(GoFile, GoFunction, Go); make_file!(RubyFile, RubyFunction, Ruby); - #[cfg(test)] mod lang_tests { // macro that auto genertes the test parse__file_time -macro_rules! make_file_time_test { - ($name:ident, $extname:ident, $function:ident) => { - #[test] - fn $name() { - let mut file = std::env::current_dir().unwrap(); - file.push("src"); - file.push("test_functions.".to_string() + stringify!($extname)); - let file = std::fs::read_to_string(file.clone()) - .expect(format!("could not read file {:?}", file).as_str()); - let start = std::time::Instant::now(); - let ok = $function::find_function_in_file(&file, "empty_test"); - let end = std::time::Instant::now(); - match &ok { - Ok(hist) => { - for i in hist { - println!("{}", i); + macro_rules! make_file_time_test { + ($name:ident, $extname:ident, $function:ident) => { + #[test] + fn $name() { + let mut file = std::env::current_dir().unwrap(); + file.push("src"); + file.push("test_functions.".to_string() + stringify!($extname)); + let file = std::fs::read_to_string(file.clone()) + .expect(format!("could not read file {:?}", file).as_str()); + let start = std::time::Instant::now(); + let ok = $function::find_function_in_file(&file, "empty_test"); + let end = std::time::Instant::now(); + match &ok { + Ok(hist) => { + for i in hist { + println!("{}", i); + } + } + Err(e) => { + println!("{}", e); } } - Err(e) => { - println!("{}", e); - } + println!("{} took {:?}", stringify!($name), end - start); + assert!(ok.is_ok()); } - println!("{} took {:?}", stringify!($name), end - start); - assert!(ok.is_ok()); - } - }; -} + }; + } use super::*; make_file_time_test!(python_parses, py, python); diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 98e05747..ee46e0fc 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -150,7 +150,7 @@ pub(crate) fn find_function_in_file( .to_string() .lines() .map(|l| { - let t = format!("{}: {}\n", start_s, l,); + let t = format!("{start_s}: {l}\n",); start_s += 1; t }) diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 0819fdcf..63b621cb 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -114,7 +114,7 @@ pub(crate) fn find_function_in_file( .lines() .map(|l| { starts += 1; - format!("{}: {}\n", starts, l,) + format!("{starts}: {l}\n",) }) .collect(), bottom: format!( @@ -163,7 +163,7 @@ pub(crate) fn find_function_in_file( .lines() .map(|l| { starts += 1; - format!("{}: {}\n", starts, l,) + format!("{starts}: {l}\n",) }) .collect(), args: f diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index b55940a2..f4443992 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -106,7 +106,7 @@ impl RustParentFunction { "arguments".to_string(), self.arguments .iter() - .map(|(k, v)| format!("{}: {}", k, v)) + .map(|(k, v)| format!("{k}: {v}")) .collect::>() .join(","), ); @@ -314,7 +314,7 @@ pub(crate) fn find_function_in_file( .lines() .map(|l| { start += 1; - format!("{}: {}\n", start, l,) + format!("{start}: {l}\n",) }) .collect(); let body = contents.trim_end().to_string(); @@ -406,7 +406,7 @@ fn get_stuff( .lines() .map(|l| { start_lines += 1; - format!("{}: {}\n", start_lines, l,) + format!("{start_lines}: {l}\n",) }) .collect::() .trim_end() diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 3aa598c1..bd380d9c 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -202,22 +202,22 @@ pub fn get_function_history( #[cfg(feature = "unstable")] Language::Go => { if !path.ends_with(".go") { - Err(format!("file is not a go file: {}", path))?; + Err(format!("file is not a go file: {path}"))?; } } Language::Python => { if !path.ends_with(".py") { - Err(format!("file is not a python file: {}", path))?; + Err(format!("file is not a python file: {path}"))?; } } Language::Rust => { if !path.ends_with(".rs") { - Err(format!("file is not a rust file: {}", path))?; + Err(format!("file is not a rust file: {path}"))?; } } Language::Ruby => { if !path.ends_with(".rb") { - Err(format!("file is not a ruby file: {}", path))?; + Err(format!("file is not a ruby file: {path}"))?; } } Language::All => { @@ -227,7 +227,7 @@ pub fn get_function_history( || !path.ends_with(".h") || !path.ends_with(".rb") { - Err(format!("file is not supported: {}", path))?; + Err(format!("file is not supported: {path}"))?; } } } @@ -350,7 +350,7 @@ pub fn get_git_commit_hashes() -> Result, Box> { #[inline] fn find_file_in_commit(commit: &str, file_path: &str) -> Result> { let commit_history = Command::new("git") - .args(format!("show {}:{}", commit, file_path).split(' ')) + .args(format!("show {commit}:{file_path}").split(' ')) .output()?; if !commit_history.stderr.is_empty() { Err(String::from_utf8_lossy(&commit_history.stderr))?; @@ -374,7 +374,7 @@ fn find_function_in_commit_with_filetype( } let file_list = String::from_utf8_lossy(&command.stdout).to_string(); if file_list.is_empty() { - return Err(format!("no files found for commit {} in git ouput", commit))?; + return Err(format!("no files found for commit {commit} in git ouput"))?; } for file in file_list.split('\n') { match filetype { @@ -486,7 +486,7 @@ fn find_function_in_commit_with_filetype( .filter_map(|(path, files)| { let mut file_types = Vec::new(); for file in files { - let file_path = format!("{}/{}", path, file); + let file_path = format!("{path}/{file}"); let file_contents = find_file_in_commit(commit, &file_path).ok()?; file_types.push((file_path, file_contents)); @@ -620,9 +620,9 @@ mod tests { println!("time taken: {}", after.num_seconds()); match &output { Ok(functions) => { - println!("{}", functions); + println!("{functions}"); } - Err(e) => println!("{}", e), + Err(e) => println!("{e}"), } assert!(output.is_ok()); } @@ -649,8 +649,8 @@ mod tests { &languages::Language::Rust, ); match &output { - Ok(output) => println!("{}", output), - Err(error) => println!("{}", error), + Ok(output) => println!("{output}"), + Err(error) => println!("{error}"), } assert!(output.is_err()); } @@ -685,9 +685,9 @@ mod tests { println!("time taken: {}", after.num_seconds()); match &output { Ok(functions) => { - println!("{}", functions); + println!("{functions}"); } - Err(e) => println!("-{}-", e), + Err(e) => println!("-{e}-"), } assert!(output.is_ok()); } @@ -708,12 +708,12 @@ mod tests { // } match &output { Ok(functions) => { - println!("{}", functions); + println!("{functions}"); functions.get_commit().files.iter().for_each(|file| { - println!("{}", file); + println!("{file}"); }); } - Err(e) => println!("{}", e), + Err(e) => println!("{e}"), } assert!(output.is_ok()); } @@ -734,9 +734,9 @@ mod tests { println!("time taken: {}", after.num_seconds()); match &output { Ok(functions) => { - println!("{}", functions); + println!("{functions}"); } - Err(e) => println!("{}", e), + Err(e) => println!("{e}"), } assert!(output.is_ok()); let output = output.unwrap(); @@ -781,9 +781,9 @@ mod tests { println!("time taken: {}", after.num_seconds()); match &t { Ok(functions) => { - println!("{:?}", functions); + println!("{functions:?}"); } - Err(e) => println!("{}", e), + Err(e) => println!("{e}"), } assert!(t.is_ok()); } @@ -801,8 +801,8 @@ mod tests { let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); match &output { - Ok(functions) => println!("{}", functions), - Err(e) => println!("{}", e), + Ok(functions) => println!("{functions}"), + Err(e) => println!("{e}"), } assert!(output.is_ok()); } @@ -825,7 +825,7 @@ mod tests { after = Utc::now() - now; println!("time taken to filter {}", after.num_seconds()); match &new_output { - Ok(res) => println!("{}", res), + Ok(res) => println!("{res}"), Err(e) => println!("{e}"), } let new_output = output.filter_by(&Filter::PLFilter(LanguageFilter::Rust( @@ -834,7 +834,7 @@ mod tests { after = Utc::now() - now; println!("time taken to filter {}", after.num_seconds()); match &new_output { - Ok(res) => println!("{}", res), + Ok(res) => println!("{res}"), Err(e) => println!("{e}"), } assert!(new_output.is_ok()); @@ -851,7 +851,7 @@ mod tests { ); match f1 { Ok(_) => println!("filter 1 ok"), - Err(e) => println!("error: {}", e), + Err(e) => println!("error: {e}"), } let f2 = filter_by!( repo, @@ -859,7 +859,7 @@ mod tests { ); match f2 { Ok(_) => println!("filter 2 ok"), - Err(e) => println!("error: {}", e), + Err(e) => println!("error: {e}"), } let f3 = filter_by!( repo, @@ -868,7 +868,7 @@ mod tests { ); match f3 { Ok(_) => println!("filter 3 ok"), - Err(e) => println!("error: {}", e), + Err(e) => println!("error: {e}"), } } } diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 13227db3..196b6933 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -97,13 +97,13 @@ impl FileTrait for FileType { impl fmt::Display for FileType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Rust(file) => write!(f, "{}", file), - Self::Python(file) => write!(f, "{}", file), + Self::Rust(file) => write!(f, "{file}"), + Self::Python(file) => write!(f, "{file}"), // #[cfg(feature = "c_lang")] // Self::C(file) => write!(f, "{}", file), #[cfg(feature = "unstable")] - Self::Go(file) => write!(f, "{}", file), - Self::Ruby(file) => write!(f, "{}", file), + Self::Go(file) => write!(f, "{file}"), + Self::Ruby(file) => write!(f, "{file}"), } } } From 9253b11db704303d481ebdd23b68d9f642f890f3 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Fri, 4 Nov 2022 18:13:36 +0000 Subject: [PATCH 102/172] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9971d589..08913564 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ All notable changes to this project will be documented in this file. ### Gui - Added scrollbar to command builder & now supports other languages +- Started working on clickable dates/commits using list ### Lib From 7fd298885917f3c8f5235e5c0fae290b7b89c382 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Fri, 4 Nov 2022 15:45:14 -0400 Subject: [PATCH 103/172] removed/turned unwraps into expects --- TODO.md | 1 + cargo-function-history/src/app/mod.rs | 9 ++++++--- function_history_backend_thread/src/lib.rs | 2 +- git-function-history-gui/src/lib.rs | 6 +++--- git-function-history-gui/src/main.rs | 8 +++++--- git-function-history-lib/src/languages/rust.rs | 12 +++++++++--- 6 files changed, 25 insertions(+), 13 deletions(-) diff --git a/TODO.md b/TODO.md index 9b1bbff4..9149e93e 100644 --- a/TODO.md +++ b/TODO.md @@ -26,6 +26,7 @@ - [/] add support for other languages (currently only supports rust) - [x] save search queries and filters to a file - [ ] rework the way filters and filefilters are handled ie maybe use a builder pattern + - [ ] remove all potentially panicking code - release 7.0: - python: diff --git a/cargo-function-history/src/app/mod.rs b/cargo-function-history/src/app/mod.rs index 6de0feae..17f0b829 100644 --- a/cargo-function-history/src/app/mod.rs +++ b/cargo-function-history/src/app/mod.rs @@ -261,7 +261,7 @@ impl App { self.channels .0 .send(FullCommand::Search(name.to_string(), file, filter, lang)) - .unwrap(); + .expect("could not send message in thread") } else { self.status = Status::Error("No function name given".to_string()); } @@ -357,7 +357,7 @@ impl App { thing: self.cmd_output.clone(), filter, })) - .unwrap(); + .expect("could not send message in thread") } "list" => { self.status = Status::Loading; @@ -376,7 +376,10 @@ impl App { } }; if let Some(list) = list { - self.channels.0.send(list).unwrap(); + self.channels + .0 + .send(list) + .expect("could not send message in thread") } } other => { diff --git a/function_history_backend_thread/src/lib.rs b/function_history_backend_thread/src/lib.rs index edb0679a..bbb98728 100644 --- a/function_history_backend_thread/src/lib.rs +++ b/function_history_backend_thread/src/lib.rs @@ -161,7 +161,7 @@ pub fn command_thread( if log { log::info!("thread finished in {}s", now.elapsed().as_secs()); } - tx_t.send(msg).unwrap(); + tx_t.send(msg).expect("could not send message in thread") } } }); diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index 1d96ed9b..55d04cfa 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -513,7 +513,7 @@ impl eframe::App for MyEguiApp { thing: self.cmd_output.clone(), filter, })) - .unwrap(); + .expect("could not send message in thread"); } } } @@ -680,7 +680,7 @@ impl eframe::App for MyEguiApp { self.filter.clone(), Language::Rust, )) - .unwrap(); + .expect("could not send message in thread"); } } Command::List => { @@ -704,7 +704,7 @@ impl eframe::App for MyEguiApp { self.channels .0 .send(FullCommand::List(self.list_type)) - .unwrap(); + .expect("could not send message in thread"); } } } diff --git a/git-function-history-gui/src/main.rs b/git-function-history-gui/src/main.rs index 2870f763..8430cba6 100644 --- a/git-function-history-gui/src/main.rs +++ b/git-function-history-gui/src/main.rs @@ -1,5 +1,6 @@ use eframe::{epaint::Vec2, run_native}; use git_function_history_gui::MyEguiApp; +use image::ImageFormat::Png; use std::sync::mpsc; fn main() { let (tx_t, rx_m) = mpsc::channel(); @@ -8,10 +9,11 @@ fn main() { "git-function-history-gui", simple_file_logger::LogLevel::Info, ) - .unwrap(); - use image::ImageFormat::Png; + .expect("could not intialize logger"); + const ICON: &[u8] = include_bytes!("../resources/icon1.png"); - let icon = image::load_from_memory_with_format(ICON, Png).unwrap(); + let icon = + image::load_from_memory_with_format(ICON, Png).expect("could not load image for icon"); function_history_backend_thread::command_thread(rx_t, tx_t, true); let native_options = eframe::NativeOptions { initial_window_size: Some(Vec2::new(800.0, 600.0)), diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index f4443992..0768db19 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -280,7 +280,10 @@ pub(crate) fn find_function_in_file( let generics = get_genrerics_and_lifetime(&function); let attr = get_doc_comments_and_attrs(&function); parent_fn.push(RustParentFunction { - name: function.name().unwrap().to_string(), + name: function + .name() + .expect("could not retrieve function name") + .to_string(), lifetime: generics.1, generics: generics.0, top: stuff.1 .0, @@ -319,7 +322,10 @@ pub(crate) fn find_function_in_file( .collect(); let body = contents.trim_end().to_string(); let function = RustFunction { - name: f.name().unwrap().to_string(), + name: f + .name() + .expect("could not retrieve function name") + .to_string(), body, block: parent_block, function: parent_fn, @@ -353,7 +359,7 @@ fn get_function_asts(name: &str, file: &str, functions: &mut Vec) { .syntax() .descendants() .filter_map(ast::Fn::cast) - .filter(|function| function.name().unwrap().text() == name) + .filter(|function| function.name().map_or(false, |n| n.text() == name)) .for_each(|function| functions.push(function)); } #[inline] From 6046b3da1a9ff9a842b89ffe8f590977a17bacf4 Mon Sep 17 00:00:00 2001 From: mendel rubin Date: Sat, 5 Nov 2022 22:17:57 -0400 Subject: [PATCH 104/172] fixed bug where rayon was trying to be imported when parelel feature not enabled --- git-function-history-lib/src/types.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 196b6933..cf115f7e 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -1,7 +1,6 @@ use chrono::{DateTime, FixedOffset}; -use rayon::prelude::IntoParallelRefIterator; #[cfg(feature = "parallel")] -use rayon::prelude::ParallelIterator; +use rayon::prelude::{ParallelIterator, IntoParallelRefIterator}; use std::{ collections::HashMap, error::Error, From 3e5fafd86bbe1a228df51fbf17776b4006db4e60 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 6 Nov 2022 17:58:33 -0500 Subject: [PATCH 105/172] updateing markdownstuffs --- TODO.md | 2 ++ git-function-history-gui/README.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/TODO.md b/TODO.md index 9149e93e..135eaf12 100644 --- a/TODO.md +++ b/TODO.md @@ -41,3 +41,5 @@ - tui: - [ ] make list command a table wiht rows and columns for date, commit, author, message, etc - [ ] (possibly) use tree sitter to provide syntax highlighting + - lib: + - [ ] possibly stop using Commmad::new("git") and use https://crates.io/crates/git_rs OR https://crates.io/crates/rs-git-lib OR https://crates.io/crates/gitoxide, to imporve performance with program compibilty assistant sevice on windows diff --git a/git-function-history-gui/README.md b/git-function-history-gui/README.md index 71a45114..4bb6ca80 100644 --- a/git-function-history-gui/README.md +++ b/git-function-history-gui/README.md @@ -26,7 +26,7 @@ Under Linux you may need to install the following packages: - libssl-dev On ubuntu you can install them with: -`sudo apt-get install -y libclang-dev libgtk-3-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libspeechd-dev libxkbcommon-dev libssl-dev` +`sudo apt install -y libclang-dev libgtk-3-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libspeechd-dev libxkbcommon-dev libssl-dev` ## Usage From 3045812e50c7b0ccd0049a2f4ca550479ec3d4e0 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 6 Nov 2022 19:20:42 -0500 Subject: [PATCH 106/172] bumped gosyn version --- git-function-history-lib/Cargo.toml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index c689b1f7..3ab9121f 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -24,8 +24,11 @@ rustpython-parser = "0.1.2" # for end_lines but can't be publsihed b/c git depenency # rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "77b821a1941019fe34f73ce17cea013ae1b98fd0" } lib-ruby-parser = "3.0.12" -gosyn = {version = "0.1.1", optional = true} +gosyn = {version = "0.2.0", optional = true} # can't be published b/c git dependency # javaparser = {git = "https://github.com/tanin47/javaparser.rs", optional = true} cfg-if = "1.0.0" -cached = {version = "0.40.0", optional = true} \ No newline at end of file +cached = {version = "0.40.0", optional = true} +# both unix only right now +# rs-git-lib = "0.2.1" +# git_rs = "0.1.0" \ No newline at end of file From 199e49a94d21a4ba16683c6f69a316062bd19a70 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Tue, 8 Nov 2022 17:39:45 -0500 Subject: [PATCH 107/172] started working on using gitoxide very messy/hacky right now --- function_history_backend_thread/src/lib.rs | 2 +- git-function-history-lib/Cargo.toml | 9 +- git-function-history-lib/src/lib.rs | 432 +++++++++++++-------- git-function-history-lib/src/types.rs | 2 +- 4 files changed, 283 insertions(+), 162 deletions(-) diff --git a/function_history_backend_thread/src/lib.rs b/function_history_backend_thread/src/lib.rs index bbb98728..56c968d7 100644 --- a/function_history_backend_thread/src/lib.rs +++ b/function_history_backend_thread/src/lib.rs @@ -97,7 +97,7 @@ pub fn command_thread( filter ); } - match get_function_history(&name, &file, &filter, &lang) { + match get_function_history(name, &file, &filter, lang) { Ok(functions) => { if log { log::info!("Found functions"); diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 3ab9121f..5f052d55 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -18,7 +18,7 @@ cache = ["dep:cached"] [dependencies] chrono = "0.4.22" -ra_ap_syntax = "0.0.137" +ra_ap_syntax = "0.0.138" rayon = { version = "1.5.3", optional = true } rustpython-parser = "0.1.2" # for end_lines but can't be publsihed b/c git depenency @@ -29,6 +29,7 @@ gosyn = {version = "0.2.0", optional = true} # javaparser = {git = "https://github.com/tanin47/javaparser.rs", optional = true} cfg-if = "1.0.0" cached = {version = "0.40.0", optional = true} -# both unix only right now -# rs-git-lib = "0.2.1" -# git_rs = "0.1.0" \ No newline at end of file +gitoxide-core = "0.19.0" +git-repository = { version = "0.27.0", default-features = false } +git-object = "0.22.1" +crossbeam-channel = "0.5.6" \ No newline at end of file diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index bd380d9c..8e30273b 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -17,15 +17,45 @@ pub mod languages; /// Different types that can extracted from the result of `get_function_history`. pub mod types; +macro_rules! get_item_from { + ($oid:expr, $repo:expr, $typs:ident) => { + git_repository::hash::ObjectId::from($oid) + .attach(&$repo) + .object()? + .$typs()? + }; +} +macro_rules! get_item_from_oid_option { + ($oid:expr, $repo:expr, $typs:ident) => { + // use git_repository; + git_repository::hash::ObjectId::from($oid) + .attach(&$repo) + // .map(|id| id.attach(&repo))? + .object() + .ok()? + .$typs() + .ok() + }; +} // static mut file_count: usize = 0; #[cfg(feature = "cache")] use cached::proc_macro::cached; +use chrono::{DateTime, NaiveDateTime, Utc}; use languages::{rust, LanguageFilter, PythonFile, RubyFile, RustFile}; +use rayon::prelude::IntoParallelIterator; #[cfg(feature = "parallel")] use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; -use std::{error::Error, process::Command}; +use crossbeam_channel::{bounded, Receiver, Sender}; +use git_repository::{prelude::ObjectIdExt, ObjectId}; +use std::{ + error::Error, + process::Command, + sync::{Arc, Mutex}, + thread::{sleep, spawn}, + time::Duration, fmt, path::PathBuf, +}; // #[cfg(feature = "c_lang")] // use languages::CFile; @@ -106,160 +136,115 @@ pub enum Filter { /// /// ``` /// use git_function_history::{get_function_history, Filter, FileFilterType, Language}; -/// let t = get_function_history("empty_test", &FileFilterType::Absolute("src/test_functions.rs".to_string()), &Filter::None, &Language::Rust).unwrap(); +/// let t = get_function_history("empty_test", &FileFilterType::Absolute("src/test_functions.rs".to_string()), &Filter::None, language::Rust).unwrapexit(); /// ``` #[allow(clippy::too_many_lines)] // TODO: split this function into smaller functions pub fn get_function_history( - name: &str, + name: String, file: &FileFilterType, filter: &Filter, - langs: &languages::Language, + langs: languages::Language, ) -> Result> { // chack if name is empty if name.is_empty() { Err("function name is empty")?; } - // check if git is installed - Command::new("git").arg("--version").output()?; - // get the commit hitory - let mut command = Command::new("git"); - command.arg("log"); - command.arg("--pretty=%H;%aD;%aN;%aE;%s"); - command.arg("--date=rfc2822"); - match filter { - Filter::CommitHash(hash) => { - command.arg(hash); - command.arg("-n"); - command.arg("1"); - } - Filter::Date(date) => { - command.arg("--since"); - command.arg(date); - command.arg("--max-count=1"); - } - Filter::DateRange(start, end) => { - command.arg("--since"); - command.arg(start); - command.arg("--until"); - command.arg(end); - } - Filter::Author(author) => { - command.arg("--author"); - command.arg(author); - } - Filter::AuthorEmail(email) => { - command.arg("--author"); - command.arg(email); - } - Filter::Message(message) => { - command.arg("--grep"); - command.arg(message); - } - Filter::None => {} - _ => { - Err("filter not supported")?; - } - } - let output = command.output()?; - if !output.stderr.is_empty() { - return Err(String::from_utf8(output.stderr)?)?; - } - let stdout = String::from_utf8(output.stdout)?; - let commits = stdout - .lines() - .map(|line| { - let mut parts = line.split(';'); - let id = parts - .next() - .unwrap_to_error_sync("no id found in git command output"); - let date = parts - .next() - .unwrap_to_error_sync("date is missing from git command output"); - let author = parts - .next() - .unwrap_to_error_sync("author is missing from git command output"); - let email = parts - .next() - .unwrap_to_error_sync("email is missing from git command output"); - let message = parts - .next() - .unwrap_to_error_sync("message is missing from git command output"); - Ok((id?, date?, author?, email?, message?)) + let repo = git_repository::discover(".")?; + let mut tips = vec![]; + let head = repo.head_commit().unwrapexit(); + tips.push(head.id); + let commit_iter = repo.rev_walk(tips); + let commits = commit_iter + .all() + .unwrapexit() + .filter_map(|i| match i { + Ok(i) => get_item_from_oid_option!(i, &repo, try_into_commit), + Err(_) => None, }) - .collect::, Box>>()?; - let mut file_history = FunctionHistory::new(String::from(name), Vec::new()); - let err = "no history found".to_string(); - // check if file is a rust file - if let FileFilterType::Absolute(path) | FileFilterType::Relative(path) = &file { - match langs { - // #[cfg(feature = "c_lang")] - // Language::C => { - // if !path.ends_with(".c") && !path.ends_with(".h") { - // Err(format!("file is not a c file: {}", path))?; - // } - // } - #[cfg(feature = "unstable")] - Language::Go => { - if !path.ends_with(".go") { - Err(format!("file is not a go file: {path}"))?; - } + .collect::>(); + let closest_date = (0, Utc::now()); + + let commits = commits + .iter() + .map(|i| { + let tree = i.tree().unwrapexit().id; + let time = i.time().unwrapexit(); + let time = DateTime::::from_utc(NaiveDateTime::from_timestamp(time.seconds_since_unix_epoch.into(), 0), Utc); + let authorinfo = i.author().unwrapexit(); + let author = authorinfo.name.to_string(); + let email = authorinfo.email.to_string(); + let messages = i.message().unwrapexit(); + let mut message = messages.title.to_string(); + if let Some(i) = messages.body { + message.push_str(i.to_string().as_str()); } - Language::Python => { - if !path.ends_with(".py") { - Err(format!("file is not a python file: {path}"))?; + let commit = i.id().to_hex().to_string(); + let metadata = (message, commit, author, email, time); + + (tree, metadata) + }) + .filter(|(_, metadata)| { + match filter { + Filter::CommitHash(hash) => *hash == metadata.1, + Filter::Date(date) => { + // if closest_date + // let date = date.parse::>().unwrapexit(); + // let cmp = DateTime::::from_utc(NaiveDateTime::from_timestamp(metadata.4.seconds_since_unix_epoch.into(), 0), Utc); + false } - } - Language::Rust => { - if !path.ends_with(".rs") { - Err(format!("file is not a rust file: {path}"))?; + Filter::DateRange(start, end) => { + // let date = metadata.4.seconds_since_unix_epoch; + let date = metadata.4; + let start = DateTime::parse_from_rfc2822(start) + .map(|i| i.with_timezone(&Utc)) + .unwrapexit(); + let end = DateTime::parse_from_rfc2822(end) + .map(|i| i.with_timezone(&Utc)) + .unwrapexit(); + start <= date && date <= end } - } - Language::Ruby => { - if !path.ends_with(".rb") { - Err(format!("file is not a ruby file: {path}"))?; + Filter::Author(author) => *author == metadata.2, + Filter::AuthorEmail(email) => *email == metadata.3, + Filter::Message(message) => { + metadata.0.contains(message) + || message.contains(&metadata.0) + || message == &metadata.0 } + Filter::None => true, + _ => false, } - Language::All => { - if !path.ends_with(".rs") - || !path.ends_with(".py") - || !path.ends_with(".c") - || !path.ends_with(".h") - || !path.ends_with(".rb") - { - Err(format!("file is not supported: {path}"))?; - } + }) + .collect::>(); + let (tx, rx) = bounded(0); + let cloned_name = name.clone(); + spawn(move || receiver(name.clone(), langs.clone(), rx)); + let commits = commits.into_par_iter().filter_map(|i| { + // let name_c = name.clone(); + // println!("{}: ",i.1.1); + let txt = tx.clone(); + let tree = spawn(move || sender(i.0, txt)); + let tree = tree.join().unwrapexit(); + // println!("done"); + match tree { + Ok(tree) => { + // for item in tree { + // println!("file: {}\n{}", item.0, item.1); + // } + Some(Commit::new(i.1.1, tree, &i.1.4.to_rfc2822(), i.1.2, i.1.3, i.1.0)) + + } + Err(_) => { + // println!("error"); + None } } + }).collect::>(); + if commits.is_empty() { + Err("no history found")?; } - #[cfg(feature = "parallel")] - let t = commits.par_iter(); - #[cfg(not(feature = "parallel"))] - let t = commits.iter(); - file_history.commit_history = t - .filter_map(|commit| match &file { - FileFilterType::Absolute(_) - | FileFilterType::Relative(_) - | FileFilterType::None - | FileFilterType::Directory(_) => find_function_in_commit_with_filetype( - commit.0, name, file, *langs, - ) - .map_or(None, |contents| { - Some(Commit::new( - commit.0.to_string(), - contents, - commit.1, - commit.2.to_string(), - commit.3.to_string(), - commit.4.to_string(), - )) - }), - }) - .collect(); - if file_history.commit_history.is_empty() { - return Err(err)?; - } - Ok(file_history) + let fh = FunctionHistory::new(cloned_name, commits); + Ok(fh) } /// used for the `get_function_history` macro internally (you don't have to touch this) @@ -281,6 +266,98 @@ impl Default for MacroOpts<'_> { } } +fn sender( + id: ObjectId, + c: Sender, bool)>>>, +) -> Result, Box> { + loop { + let id = Arc::new(Mutex::new((id, Vec::new(), false))); + c.send(Arc::clone(&id))?; + loop { + { + let id = id.lock().unwrapexit(); + if id.2 { + return Ok(id.1.clone()); + } + } + sleep(Duration::from_millis(1000)); + } + } +} + +fn receiver( + name: String, + langs: Language, + c: Receiver, bool)>>>, +) { + let repo = git_repository::discover(".").unwrapexit(); + for r in c { + let mut data = r.lock().unwrapexit(); + let (objid, _, _ ) = data.clone(); + let object = repo.find_object(objid).unwrapexit(); + let tree = object.into_tree(); + // println!("traverse_tree"); + let files = traverse_tree(&tree, &repo, &name,"".to_string(), langs).unwrapexit(); + // println!("tree traverse_tree"); + data.1 = files; + data.2 = true; + } +} + +fn traverse_tree( + tree: &git_repository::Tree<'_>, + repo: &git_repository::Repository, + name: &str, + path: String, + langs: Language, +) -> Result, Box> { + // println!("traverse_tree in"); + let treee_iter = tree.iter(); + let mut files: Vec<(String, String)> = Vec::new(); + let mut ret = Vec::new(); + for i in treee_iter { + let i = i.unwrapexit(); + match &i.mode() { + git_object::tree::EntryMode::Tree => { + let new = get_item_from!(i.oid(), &repo, try_into_tree); + let path_new = PathBuf::from(path.clone()).join(i.filename().to_string()); + // println!("new tree"); + ret.extend(traverse_tree(&new, repo, name, path_new.to_str().unwrapexit().to_string(), langs)?); + // println!("new tree done"); + } + git_object::tree::EntryMode::Blob => { + if !i.filename().to_string().ends_with(".rs") { + continue; + } + // println!("{path}/{}", i.filename().to_string()); + // unsafe { + // COUNT += 1; + // } + let obh = repo.find_object(i.oid())?; + // i.inner. + let objref = git_object::ObjectRef::from_bytes(obh.kind, &obh.data)?; + let blob = objref.into_blob(); + if let Some(blob) = blob { + files.push(( + i.filename().to_string(), + String::from_utf8_lossy(blob.data).to_string(), + )); + } + } + _ => { + println!("unknown"); + } + } + } + // println!("parsing"); + ret.extend(find_function_in_files_with_commit( + files, + name.to_string(), + langs, + )); + // println!("traverse_tree out"); + Ok(ret) +} /// macro to get the history of a function /// wrapper around the `get_function_history` function /// @@ -316,10 +393,10 @@ macro_rules! get_function_history { opts.$variant = $value; )* get_function_history( - &opts.name, + opts.name.to_string(), &opts.file, &opts.filter, - &opts.language + opts.language ) }}; } @@ -511,6 +588,7 @@ fn find_function_in_file_with_commit( name: &str, langs: Language, ) -> Result> { + // println!("finding function {} in file {}", name, file_path); // unsafe { // file_count += 1; // } @@ -573,12 +651,24 @@ fn find_function_in_files_with_commit( name: String, langs: Language, ) -> Vec { + // println!("files: ",); #[cfg(feature = "parallel")] let t = files.par_iter(); - #[cfg(not(feature = "parallel"))] + // #[cfg(not(feature = "parallel"))] let t = files.iter(); + // println!("finding function {} in files", name); t.filter_map(|(file_path, fc)| { - find_function_in_file_with_commit(file_path, fc, &name, langs).ok() + // println!("fparsing ile_path: {}", file_path); + match find_function_in_file_with_commit(file_path, fc, &name, langs) { + Ok(file) => { + // println!("file: {:?}", file); + Some(file)}, + Err(e) => { + // println!("error: {}", e); + None + } + } + // println!("parsed file_path: {}", file_path); }) .collect() } @@ -611,10 +701,10 @@ mod tests { fn found_function() { let now = Utc::now(); let output = get_function_history( - "empty_test", + "empty_test".to_string(), &FileFilterType::Relative("src/test_functions.rs".to_string()), &Filter::None, - &languages::Language::Rust, + languages::Language::Rust, ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); @@ -629,10 +719,10 @@ mod tests { #[test] fn git_installed() { let output = get_function_history( - "empty_test", + "empty_test".to_owned(), &FileFilterType::Absolute("src/test_functions.rs".to_string()), &Filter::None, - &languages::Language::Rust, + languages::Language::Rust, ); // assert that err is "not git is not installed" if output.is_err() { @@ -643,10 +733,10 @@ mod tests { #[test] fn not_found() { let output = get_function_history( - "Not_a_function", + "Not_a_function".to_string(), &FileFilterType::None, &Filter::None, - &languages::Language::Rust, + languages::Language::Rust, ); match &output { Ok(output) => println!("{output}"), @@ -658,10 +748,10 @@ mod tests { #[test] fn not_rust_file() { let output = get_function_history( - "empty_test", + "empty_test".to_string(), &FileFilterType::Absolute("src/test_functions.txt".to_string()), &Filter::None, - &languages::Language::Rust, + languages::Language::Rust, ); assert!(output.is_err()); assert!(output @@ -673,13 +763,13 @@ mod tests { fn test_date() { let now = Utc::now(); let output = get_function_history( - "empty_test", + "empty_test".to_string(), &FileFilterType::None, &Filter::DateRange( "27 Sep 2022 11:27:23 -0400".to_owned(), "04 Oct 2022 23:45:52 +0000".to_owned(), ), - &languages::Language::Rust, + languages::Language::Rust, ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); @@ -696,10 +786,10 @@ mod tests { fn expensive_tes() { let now = Utc::now(); let output = get_function_history( - "empty_test", + "empty_test".to_string(), &FileFilterType::None, &Filter::None, - &languages::Language::All, + languages::Language::All, ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); @@ -722,13 +812,13 @@ mod tests { fn python() { let now = Utc::now(); let output = get_function_history( - "empty_test", + "empty_test".to_string(), &FileFilterType::Relative("src/test_functions.py".to_string()), &Filter::DateRange( "03 Oct 2022 11:27:23 -0400".to_owned(), "04 Oct 2022 23:45:52 +0000".to_owned(), ), - &languages::Language::Python, + languages::Language::Python, ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); @@ -739,7 +829,7 @@ mod tests { Err(e) => println!("{e}"), } assert!(output.is_ok()); - let output = output.unwrap(); + let output = output.unwrapexit(); let commit = output.get_commit(); let file = commit.get_file(); let _functions = file.get_functions(); @@ -756,7 +846,7 @@ mod tests { // "03 Oct 2022 11:27:23 -0400".to_owned(), // "05 Oct 2022 23:45:52 +0000".to_owned(), // ), - // &languages::Language::C, + // languages::Language::C, // ); // let after = Utc::now() - now; // println!("time taken: {}", after.num_seconds()); @@ -796,7 +886,7 @@ mod tests { "empty_test", &FileFilterType::Relative("src/test_functions.go".to_string()), &Filter::None, - &languages::Language::Go, + languages::Language::Go, ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); @@ -872,3 +962,33 @@ mod tests { } } } + +trait unwrapexit { + fn unwrapexit(self) -> T; +} + +impl unwrapexit for Result { + fn unwrapexit(self) -> T { + match self { + Ok(t) => t, + Err(e) => { + println!("{:?}", e); + std::process::exit(1); + } + } + } +} + +impl unwrapexit for Option { + fn unwrapexit(self) -> T { + match self { + Some(t) => t, + None => { + println!("None"); + std::process::exit(1); + } + } + } +} + + diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index cf115f7e..b9112c48 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -1,6 +1,6 @@ use chrono::{DateTime, FixedOffset}; #[cfg(feature = "parallel")] -use rayon::prelude::{ParallelIterator, IntoParallelRefIterator}; +use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use std::{ collections::HashMap, error::Error, From 32e7f9c4f507a8398f79ad90ccbe4d55e8bf337e Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Tue, 8 Nov 2022 20:42:57 -0500 Subject: [PATCH 108/172] most things working fixed go stuff neeed to remove unwraps and other panicking stufff needs a lot of cleanup --- git-function-history-lib/src/languages/go.rs | 22 +- git-function-history-lib/src/lib.rs | 447 ++++++------------- 2 files changed, 150 insertions(+), 319 deletions(-) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index f1674f28..bab6190a 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -122,16 +122,15 @@ pub(crate) fn find_function_in_file( lines.0 = start_line; lines.1 = end_line; + // see if the first parameter has a name: let mut parameters = func.typ.params.list.get(0).map_or_else( || GoParameter::Type(vec![]), |param| { if param.name.is_empty() { GoParameter::Type(match ¶m.typ { - gosyn::ast::Expression::Type(gosyn::ast::Type::Ident( - ident, - )) => { - vec![ident.name.name.clone()] + gosyn::ast::Expression::Ident(ident) => { + vec![ident.name.clone()] } _ => { vec![] @@ -139,9 +138,7 @@ pub(crate) fn find_function_in_file( }) } else { let typ = match ¶m.typ { - gosyn::ast::Expression::Type(gosyn::ast::Type::Ident( - ident, - )) => ident.name.name.clone(), + gosyn::ast::Expression::Ident(ident) => ident.name.clone(), _ => String::new(), }; @@ -155,18 +152,14 @@ pub(crate) fn find_function_in_file( func.typ.params.list.iter().skip(1).for_each(|param| { if param.name.is_empty() { - if let gosyn::ast::Expression::Type(gosyn::ast::Type::Ident(ident)) = - ¶m.typ - { + if let gosyn::ast::Expression::Ident(ident) = ¶m.typ { if let GoParameter::Type(types) = &mut parameters { - types.push(ident.name.name.clone()); + types.push(ident.name.clone()); } } } else { let typ = match ¶m.typ { - gosyn::ast::Expression::Type(gosyn::ast::Type::Ident(ident)) => { - ident.name.name.clone() - } + gosyn::ast::Expression::Ident(ident) => ident.name.clone(), _ => String::new(), }; @@ -211,6 +204,7 @@ pub(crate) fn find_function_in_file( if parsed.is_empty() { return Err(format!("could not find function {name} in file"))?; } + Ok(parsed) } diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 8e30273b..3ec46a13 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -28,24 +28,20 @@ macro_rules! get_item_from { macro_rules! get_item_from_oid_option { ($oid:expr, $repo:expr, $typs:ident) => { - // use git_repository; git_repository::hash::ObjectId::from($oid) .attach(&$repo) - // .map(|id| id.attach(&repo))? .object() .ok()? .$typs() .ok() }; } -// static mut file_count: usize = 0; #[cfg(feature = "cache")] use cached::proc_macro::cached; use chrono::{DateTime, NaiveDateTime, Utc}; use languages::{rust, LanguageFilter, PythonFile, RubyFile, RustFile}; -use rayon::prelude::IntoParallelIterator; -#[cfg(feature = "parallel")] -use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; + +use rayon::prelude::{IntoParallelIterator, ParallelIterator}; use crossbeam_channel::{bounded, Receiver, Sender}; use git_repository::{prelude::ObjectIdExt, ObjectId}; @@ -54,7 +50,7 @@ use std::{ process::Command, sync::{Arc, Mutex}, thread::{sleep, spawn}, - time::Duration, fmt, path::PathBuf, + time::Duration, }; // #[cfg(feature = "c_lang")] @@ -68,6 +64,7 @@ pub use { }; /// Different filetypes that can be used to ease the process of finding functions using `get_function_history`. +/// path separator is `/`. #[derive(Debug, Clone, PartialEq, Eq)] pub enum FileFilterType { /// When you have a absolute path to a file. @@ -136,7 +133,7 @@ pub enum Filter { /// /// ``` /// use git_function_history::{get_function_history, Filter, FileFilterType, Language}; -/// let t = get_function_history("empty_test", &FileFilterType::Absolute("src/test_functions.rs".to_string()), &Filter::None, language::Rust).unwrapexit(); +/// let t = get_function_history("empty_test", &FileFilterType::Absolute("src/test_functions.rs".to_string()), &Filter::None, language::Rust).unwrap(); /// ``` #[allow(clippy::too_many_lines)] // TODO: split this function into smaller functions @@ -152,44 +149,46 @@ pub fn get_function_history( } let repo = git_repository::discover(".")?; let mut tips = vec![]; - let head = repo.head_commit().unwrapexit(); + let head = repo.head_commit().unwrap(); tips.push(head.id); let commit_iter = repo.rev_walk(tips); let commits = commit_iter .all() - .unwrapexit() + .unwrap() .filter_map(|i| match i { Ok(i) => get_item_from_oid_option!(i, &repo, try_into_commit), Err(_) => None, }) .collect::>(); - let closest_date = (0, Utc::now()); - + let _closest_date = (0, Utc::now()); let commits = commits .iter() .map(|i| { - let tree = i.tree().unwrapexit().id; - let time = i.time().unwrapexit(); - let time = DateTime::::from_utc(NaiveDateTime::from_timestamp(time.seconds_since_unix_epoch.into(), 0), Utc); - let authorinfo = i.author().unwrapexit(); + let tree = i.tree().unwrap().id; + let time = i.time().unwrap(); + let time = DateTime::::from_utc( + NaiveDateTime::from_timestamp(time.seconds_since_unix_epoch.into(), 0), + Utc, + ); + let authorinfo = i.author().unwrap(); let author = authorinfo.name.to_string(); let email = authorinfo.email.to_string(); - let messages = i.message().unwrapexit(); + let messages = i.message().unwrap(); let mut message = messages.title.to_string(); if let Some(i) = messages.body { message.push_str(i.to_string().as_str()); } let commit = i.id().to_hex().to_string(); let metadata = (message, commit, author, email, time); - (tree, metadata) }) .filter(|(_, metadata)| { match filter { Filter::CommitHash(hash) => *hash == metadata.1, - Filter::Date(date) => { + Filter::Date(_date) => { + // TODO: fix this // if closest_date - // let date = date.parse::>().unwrapexit(); + // let date = date.parse::>().unwrap(); // let cmp = DateTime::::from_utc(NaiveDateTime::from_timestamp(metadata.4.seconds_since_unix_epoch.into(), 0), Utc); false } @@ -198,10 +197,10 @@ pub fn get_function_history( let date = metadata.4; let start = DateTime::parse_from_rfc2822(start) .map(|i| i.with_timezone(&Utc)) - .unwrapexit(); + .unwrap(); let end = DateTime::parse_from_rfc2822(end) .map(|i| i.with_timezone(&Utc)) - .unwrapexit(); + .unwrap(); start <= date && date <= end } Filter::Author(author) => *author == metadata.2, @@ -218,28 +217,32 @@ pub fn get_function_history( .collect::>(); let (tx, rx) = bounded(0); let cloned_name = name.clone(); - spawn(move || receiver(name.clone(), langs.clone(), rx)); - let commits = commits.into_par_iter().filter_map(|i| { - // let name_c = name.clone(); - // println!("{}: ",i.1.1); - let txt = tx.clone(); - let tree = spawn(move || sender(i.0, txt)); - let tree = tree.join().unwrapexit(); - // println!("done"); - match tree { - Ok(tree) => { - // for item in tree { - // println!("file: {}\n{}", item.0, item.1); - // } - Some(Commit::new(i.1.1, tree, &i.1.4.to_rfc2822(), i.1.2, i.1.3, i.1.0)) - - } - Err(_) => { - // println!("error"); - None + let cloned_file = file.clone(); + spawn(move || receiver(&name, langs, &cloned_file, rx)); + let commits = commits + .into_par_iter() + .filter_map(|i| { + let txt = tx.clone(); + let tree = spawn(move || sender(i.0, txt)); + let tree = tree.join().unwrap(); + match tree { + Ok(tree) => { + if tree.is_empty() { + None?; + } + Some(Commit::new( + i.1 .1, + tree, + &i.1 .4.to_rfc2822(), + i.1 .2, + i.1 .3, + i.1 .0, + )) + } + Err(_) => None, } - } - }).collect::>(); + }) + .collect::>(); if commits.is_empty() { Err("no history found")?; } @@ -275,7 +278,7 @@ fn sender( c.send(Arc::clone(&id))?; loop { { - let id = id.lock().unwrapexit(); + let id = id.lock().unwrap(); if id.2 { return Ok(id.1.clone()); } @@ -286,19 +289,18 @@ fn sender( } fn receiver( - name: String, + name: &str, langs: Language, - c: Receiver, bool)>>>, + filetype: &FileFilterType, + c: Receiver, bool)>>>, ) { - let repo = git_repository::discover(".").unwrapexit(); + let repo = git_repository::discover(".").unwrap(); for r in c { - let mut data = r.lock().unwrapexit(); - let (objid, _, _ ) = data.clone(); - let object = repo.find_object(objid).unwrapexit(); + let mut data = r.lock().unwrap(); + let (objid, _, _) = data.clone(); + let object = repo.find_object(objid).unwrap(); let tree = object.into_tree(); - // println!("traverse_tree"); - let files = traverse_tree(&tree, &repo, &name,"".to_string(), langs).unwrapexit(); - // println!("tree traverse_tree"); + let files = traverse_tree(&tree, &repo, name, "", langs, filetype).unwrap(); data.1 = files; data.2 = true; } @@ -308,33 +310,95 @@ fn traverse_tree( tree: &git_repository::Tree<'_>, repo: &git_repository::Repository, name: &str, - path: String, + path: &str, langs: Language, + filetype: &FileFilterType, ) -> Result, Box> { - // println!("traverse_tree in"); let treee_iter = tree.iter(); let mut files: Vec<(String, String)> = Vec::new(); let mut ret = Vec::new(); for i in treee_iter { - let i = i.unwrapexit(); + let i = i.unwrap(); match &i.mode() { git_object::tree::EntryMode::Tree => { let new = get_item_from!(i.oid(), &repo, try_into_tree); - let path_new = PathBuf::from(path.clone()).join(i.filename().to_string()); - // println!("new tree"); - ret.extend(traverse_tree(&new, repo, name, path_new.to_str().unwrapexit().to_string(), langs)?); - // println!("new tree done"); + let path_new = format!("{path}/{}", i.filename()); + ret.extend(traverse_tree(&new, repo, name, &path_new, langs, filetype)?); } git_object::tree::EntryMode::Blob => { - if !i.filename().to_string().ends_with(".rs") { - continue; + let file = format!("{path}/{}", i.filename()); + match &filetype { + FileFilterType::Relative(ref path) => { + if !file.ends_with(path) { + continue; + } + } + FileFilterType::Absolute(ref path) => { + if &file == path { + continue; + } + } + FileFilterType::Directory(ref path) => { + if !file.contains(path) { + continue; + } + } + FileFilterType::None => match langs { + // #[cfg(feature = "c_lang")] + // Language::C => { + // if file.ends_with(".c") || file.ends_with(".h") { + // files.push(file); + // } + // } + #[cfg(feature = "unstable")] + Language::Go => { + if !file.ends_with(".go") { + continue; + } + } + Language::Python => { + if !file.ends_with(".py") { + continue; + } + } + Language::Rust => { + if !file.ends_with(".rs") { + continue; + } + } + Language::Ruby => { + if !file.ends_with(".rb") { + continue; + } + } + Language::All => { + cfg_if::cfg_if! { + if #[cfg(feature = "c_lang")] { + if !(file.ends_with(".c") || file.ends_with(".h") || !file.ends_with(".rs") || file.ends_with(".py") || file.ends_with(".rb")) { + continue; + } + } + else if #[cfg(feature = "unstable")] { + if !(file.ends_with(".go") || file.ends_with(".rs") || file.ends_with(".py") || file.ends_with(".rb")){ + continue + } + } + else if #[cfg(all(feature = "unstable", feature = "c_lang"))] { + if !(file.ends_with(".go") || file.ends_with(".c") || file.ends_with(".h") || file.ends_with(".rs") || file.ends_with(".py") || file.ends_with(".rb")) { + continue; + } + } + else { + if !(file.ends_with(".rs") || file.ends_with(".py") || file.ends_with(".rb")) { + continue; + } + } + + } + } + }, } - // println!("{path}/{}", i.filename().to_string()); - // unsafe { - // COUNT += 1; - // } let obh = repo.find_object(i.oid())?; - // i.inner. let objref = git_object::ObjectRef::from_bytes(obh.kind, &obh.data)?; let blob = objref.into_blob(); if let Some(blob) = blob { @@ -344,18 +408,16 @@ fn traverse_tree( )); } } - _ => { - println!("unknown"); - } + _ => {} } } - // println!("parsing"); + ret.extend(find_function_in_files_with_commit( files, name.to_string(), langs, )); - // println!("traverse_tree out"); + Ok(ret) } /// macro to get the history of a function @@ -424,163 +486,6 @@ pub fn get_git_commit_hashes() -> Result, Box> { .collect::>(); Ok(output) } -#[inline] -fn find_file_in_commit(commit: &str, file_path: &str) -> Result> { - let commit_history = Command::new("git") - .args(format!("show {commit}:{file_path}").split(' ')) - .output()?; - if !commit_history.stderr.is_empty() { - Err(String::from_utf8_lossy(&commit_history.stderr))?; - } - Ok(String::from_utf8_lossy(&commit_history.stdout).to_string()) -} - -fn find_function_in_commit_with_filetype( - commit: &str, - name: &str, - filetype: &FileFilterType, - langs: Language, -) -> Result, Box> { - // get a list of all the files in the repository - let mut files = Vec::new(); - let command = Command::new("git") - .args(["ls-tree", "-r", "--name-only", "--full-tree", commit]) - .output()?; - if !command.stderr.is_empty() { - Err(String::from_utf8_lossy(&command.stderr))?; - } - let file_list = String::from_utf8_lossy(&command.stdout).to_string(); - if file_list.is_empty() { - return Err(format!("no files found for commit {commit} in git ouput"))?; - } - for file in file_list.split('\n') { - match filetype { - FileFilterType::Relative(ref path) => { - if file.ends_with(path) { - files.push(file); - } - } - FileFilterType::Absolute(ref path) => { - if file == path { - files.push(file); - } - } - FileFilterType::Directory(ref path) => { - if path.contains(path) { - files.push(file); - } - } - FileFilterType::None => match langs { - // #[cfg(feature = "c_lang")] - // Language::C => { - // if file.ends_with(".c") || file.ends_with(".h") { - // files.push(file); - // } - // } - #[cfg(feature = "unstable")] - Language::Go => { - if file.ends_with(".go") { - files.push(file); - } - } - Language::Python => { - if file.ends_with(".py") { - files.push(file); - } - } - Language::Rust => { - if file.ends_with(".rs") { - files.push(file); - } - } - Language::Ruby => { - if file.ends_with(".rb") { - files.push(file); - } - } - Language::All => { - cfg_if::cfg_if! { - if #[cfg(feature = "c_lang")] { - if file.ends_with(".c") || file.ends_with(".h") || file.ends_with(".rs") || file.ends_with(".py") || file.ends_with(".rb") { - files.push(file); - } - } - else if #[cfg(feature = "unstable")] { - if file.ends_with(".go") || file.ends_with(".rs") || file.ends_with(".py") || file.ends_with(".rb"){ - files.push(file); - } - } - else if #[cfg(all(feature = "unstable", feature = "c_lang"))] { - if file.ends_with(".c") || file.ends_with(".h") || file.ends_with(".go") || file.ends_with(".rs") || file.ends_with(".py") || file.ends_with(".rb") { - files.push(file); - } - } - else { - if file.ends_with(".rs") || file.ends_with(".py") || file.ends_with(".rb") { - files.push(file); - } - } - - } - } - }, - } - } - if files.is_empty() { - return Err(format!( - "no files found for commit {} in matching the languages specified", - commit - ))?; - } - let err = "no function found".to_string(); - // organize the files into hierarchical structure of directories (vector of vectors) by splitting the path - let mut file_tree: Vec<(String, Vec<&str>)> = Vec::new(); - for file in files.clone() { - let mut file_path = file.split('/').collect::>(); - let name = match file_path.pop() { - Some(name) => name, - None => continue, - }; - let file_path = file_path.join("/"); - let mut file_tree_index_found = false; - for (file_tree_index, file_tree_path) in file_tree.iter().enumerate() { - if (file_tree_path).0 == file_path { - file_tree_index_found = true; - file_tree[file_tree_index].1.push(name); - break; - } - } - if !file_tree_index_found { - file_tree.push((file_path, vec![name])); - } - } - - #[cfg(feature = "parallel")] - let t = file_tree.par_iter(); - #[cfg(not(feature = "parallel"))] - let t = file_tree.iter(); - let stuffs = t - .filter_map(|(path, files)| { - let mut file_types = Vec::new(); - for file in files { - let file_path = format!("{path}/{file}"); - let file_contents = find_file_in_commit(commit, &file_path).ok()?; - - file_types.push((file_path, file_contents)); - } - - match find_function_in_files_with_commit(file_types, name.to_string(), langs) { - vec if !vec.is_empty() => Some(vec), - _ => None, - } - }) - .flat_map(|x| x) - .collect::>(); - if stuffs.is_empty() { - Err(err)?; - } - Ok(stuffs) -} fn find_function_in_file_with_commit( file_path: &str, @@ -588,10 +493,6 @@ fn find_function_in_file_with_commit( name: &str, langs: Language, ) -> Result> { - // println!("finding function {} in file {}", name, file_path); - // unsafe { - // file_count += 1; - // } let file = match langs { Language::Rust => { let functions = rust::find_function_in_file(fc, name)?; @@ -651,24 +552,12 @@ fn find_function_in_files_with_commit( name: String, langs: Language, ) -> Vec { - // println!("files: ",); - #[cfg(feature = "parallel")] - let t = files.par_iter(); + // #[cfg(feature = "parallel")] + // let t = files.par_iter(); // #[cfg(not(feature = "parallel"))] let t = files.iter(); - // println!("finding function {} in files", name); t.filter_map(|(file_path, fc)| { - // println!("fparsing ile_path: {}", file_path); - match find_function_in_file_with_commit(file_path, fc, &name, langs) { - Ok(file) => { - // println!("file: {:?}", file); - Some(file)}, - Err(e) => { - // println!("error: {}", e); - None - } - } - // println!("parsed file_path: {}", file_path); + find_function_in_file_with_commit(file_path, fc, &name, langs).ok() }) .collect() } @@ -793,13 +682,11 @@ mod tests { ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); - // unsafe { - // println!("# of files parsed: {}", file_count); - // } match &output { Ok(functions) => { println!("{functions}"); functions.get_commit().files.iter().for_each(|file| { + println!("file: {}", file.get_file_name()); println!("{file}"); }); } @@ -829,7 +716,7 @@ mod tests { Err(e) => println!("{e}"), } assert!(output.is_ok()); - let output = output.unwrapexit(); + let output = output.unwrap(); let commit = output.get_commit(); let file = commit.get_file(); let _functions = file.get_functions(); @@ -856,34 +743,14 @@ mod tests { // } // assert!(output.is_ok()); // } - - #[test] - fn parse_commit() { - let commit_hash = "d098bba8be70106060f7250b80add703b7673d0e"; - let now = Utc::now(); - let t = find_function_in_commit_with_filetype( - commit_hash, - "empty_test", - &FileFilterType::None, - languages::Language::All, - ); - let after = Utc::now() - now; - println!("time taken: {}", after.num_seconds()); - match &t { - Ok(functions) => { - println!("{functions:?}"); - } - Err(e) => println!("{e}"), - } - assert!(t.is_ok()); - } - #[test] #[cfg(feature = "unstable")] fn go() { let now = Utc::now(); + sleep(Duration::from_secs(2)); + println!("go STARTING"); let output = get_function_history( - "empty_test", + "empty_test".to_string(), &FileFilterType::Relative("src/test_functions.go".to_string()), &Filter::None, languages::Language::Go, @@ -962,33 +829,3 @@ mod tests { } } } - -trait unwrapexit { - fn unwrapexit(self) -> T; -} - -impl unwrapexit for Result { - fn unwrapexit(self) -> T { - match self { - Ok(t) => t, - Err(e) => { - println!("{:?}", e); - std::process::exit(1); - } - } - } -} - -impl unwrapexit for Option { - fn unwrapexit(self) -> T { - match self { - Some(t) => t, - None => { - println!("None"); - std::process::exit(1); - } - } - } -} - - From 79c13a090f89c5c6e7458da2aaba1b29692399f6 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 9 Nov 2022 11:37:44 -0500 Subject: [PATCH 109/172] removed arc/mutexs and sneder recievers make go faster could be opmized further in traverse tree --- function_history_backend_thread/src/lib.rs | 2 +- git-function-history-lib/Cargo.toml | 3 +- git-function-history-lib/src/lib.rs | 113 ++++++++------------- 3 files changed, 44 insertions(+), 74 deletions(-) diff --git a/function_history_backend_thread/src/lib.rs b/function_history_backend_thread/src/lib.rs index 56c968d7..bbb98728 100644 --- a/function_history_backend_thread/src/lib.rs +++ b/function_history_backend_thread/src/lib.rs @@ -97,7 +97,7 @@ pub fn command_thread( filter ); } - match get_function_history(name, &file, &filter, lang) { + match get_function_history(&name, &file, &filter, &lang) { Ok(functions) => { if log { log::info!("Found functions"); diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 5f052d55..bd21c6d6 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -31,5 +31,4 @@ cfg-if = "1.0.0" cached = {version = "0.40.0", optional = true} gitoxide-core = "0.19.0" git-repository = { version = "0.27.0", default-features = false } -git-object = "0.22.1" -crossbeam-channel = "0.5.6" \ No newline at end of file +git-object = "0.22.1" \ No newline at end of file diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 3ec46a13..40b48322 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -43,14 +43,10 @@ use languages::{rust, LanguageFilter, PythonFile, RubyFile, RustFile}; use rayon::prelude::{IntoParallelIterator, ParallelIterator}; -use crossbeam_channel::{bounded, Receiver, Sender}; use git_repository::{prelude::ObjectIdExt, ObjectId}; use std::{ error::Error, process::Command, - sync::{Arc, Mutex}, - thread::{sleep, spawn}, - time::Duration, }; // #[cfg(feature = "c_lang")] @@ -138,10 +134,10 @@ pub enum Filter { #[allow(clippy::too_many_lines)] // TODO: split this function into smaller functions pub fn get_function_history( - name: String, + name: &str, file: &FileFilterType, filter: &Filter, - langs: languages::Language, + langs: &languages::Language, ) -> Result> { // chack if name is empty if name.is_empty() { @@ -215,16 +211,11 @@ pub fn get_function_history( } }) .collect::>(); - let (tx, rx) = bounded(0); let cloned_name = name.clone(); - let cloned_file = file.clone(); - spawn(move || receiver(&name, langs, &cloned_file, rx)); let commits = commits .into_par_iter() .filter_map(|i| { - let txt = tx.clone(); - let tree = spawn(move || sender(i.0, txt)); - let tree = tree.join().unwrap(); + let tree = sender(i.0, &name, langs, file); match tree { Ok(tree) => { if tree.is_empty() { @@ -246,7 +237,7 @@ pub fn get_function_history( if commits.is_empty() { Err("no history found")?; } - let fh = FunctionHistory::new(cloned_name, commits); + let fh = FunctionHistory::new(cloned_name.to_string(), commits); Ok(fh) } @@ -271,39 +262,18 @@ impl Default for MacroOpts<'_> { fn sender( id: ObjectId, - c: Sender, bool)>>>, -) -> Result, Box> { - loop { - let id = Arc::new(Mutex::new((id, Vec::new(), false))); - c.send(Arc::clone(&id))?; - loop { - { - let id = id.lock().unwrap(); - if id.2 { - return Ok(id.1.clone()); - } - } - sleep(Duration::from_millis(1000)); - } - } -} - -fn receiver( name: &str, - langs: Language, - filetype: &FileFilterType, - c: Receiver, bool)>>>, -) { + langs: &Language, + file: &FileFilterType + +) -> Result, Box> { let repo = git_repository::discover(".").unwrap(); - for r in c { - let mut data = r.lock().unwrap(); - let (objid, _, _) = data.clone(); - let object = repo.find_object(objid).unwrap(); - let tree = object.into_tree(); - let files = traverse_tree(&tree, &repo, name, "", langs, filetype).unwrap(); - data.1 = files; - data.2 = true; - } + let object = repo.find_object(id).unwrap(); + let tree = object.into_tree(); + let files = traverse_tree(&tree, &repo, name,"", langs, file); + + files + } fn traverse_tree( @@ -311,7 +281,7 @@ fn traverse_tree( repo: &git_repository::Repository, name: &str, path: &str, - langs: Language, + langs: &Language, filetype: &FileFilterType, ) -> Result, Box> { let treee_iter = tree.iter(); @@ -415,7 +385,7 @@ fn traverse_tree( ret.extend(find_function_in_files_with_commit( files, name.to_string(), - langs, + *langs, )); Ok(ret) @@ -455,10 +425,10 @@ macro_rules! get_function_history { opts.$variant = $value; )* get_function_history( - opts.name.to_string(), + opts.name, &opts.file, &opts.filter, - opts.language + &opts.language ) }}; } @@ -491,7 +461,7 @@ fn find_function_in_file_with_commit( file_path: &str, fc: &str, name: &str, - langs: Language, + langs: &Language, ) -> Result> { let file = match langs { Language::Rust => { @@ -552,12 +522,13 @@ fn find_function_in_files_with_commit( name: String, langs: Language, ) -> Vec { - // #[cfg(feature = "parallel")] - // let t = files.par_iter(); - // #[cfg(not(feature = "parallel"))] + use rayon::iter::IntoParallelRefIterator; + #[cfg(feature = "parallel")] + let t = files.par_iter(); + #[cfg(not(feature = "parallel"))] let t = files.iter(); t.filter_map(|(file_path, fc)| { - find_function_in_file_with_commit(file_path, fc, &name, langs).ok() + find_function_in_file_with_commit(file_path, fc, &name, &langs).ok() }) .collect() } @@ -590,10 +561,10 @@ mod tests { fn found_function() { let now = Utc::now(); let output = get_function_history( - "empty_test".to_string(), + "empty_test", &FileFilterType::Relative("src/test_functions.rs".to_string()), &Filter::None, - languages::Language::Rust, + &languages::Language::Rust, ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); @@ -608,10 +579,10 @@ mod tests { #[test] fn git_installed() { let output = get_function_history( - "empty_test".to_owned(), + "empty_test", &FileFilterType::Absolute("src/test_functions.rs".to_string()), &Filter::None, - languages::Language::Rust, + &languages::Language::Rust, ); // assert that err is "not git is not installed" if output.is_err() { @@ -622,10 +593,10 @@ mod tests { #[test] fn not_found() { let output = get_function_history( - "Not_a_function".to_string(), + "Not_a_function", &FileFilterType::None, &Filter::None, - languages::Language::Rust, + &languages::Language::Rust, ); match &output { Ok(output) => println!("{output}"), @@ -637,10 +608,10 @@ mod tests { #[test] fn not_rust_file() { let output = get_function_history( - "empty_test".to_string(), + "empty_test", &FileFilterType::Absolute("src/test_functions.txt".to_string()), &Filter::None, - languages::Language::Rust, + &languages::Language::Rust, ); assert!(output.is_err()); assert!(output @@ -652,13 +623,13 @@ mod tests { fn test_date() { let now = Utc::now(); let output = get_function_history( - "empty_test".to_string(), + "empty_test", &FileFilterType::None, &Filter::DateRange( "27 Sep 2022 11:27:23 -0400".to_owned(), "04 Oct 2022 23:45:52 +0000".to_owned(), ), - languages::Language::Rust, + &languages::Language::Rust, ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); @@ -675,10 +646,10 @@ mod tests { fn expensive_tes() { let now = Utc::now(); let output = get_function_history( - "empty_test".to_string(), + "empty_test", &FileFilterType::None, &Filter::None, - languages::Language::All, + &languages::Language::All, ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); @@ -699,13 +670,13 @@ mod tests { fn python() { let now = Utc::now(); let output = get_function_history( - "empty_test".to_string(), + "empty_test", &FileFilterType::Relative("src/test_functions.py".to_string()), &Filter::DateRange( "03 Oct 2022 11:27:23 -0400".to_owned(), "04 Oct 2022 23:45:52 +0000".to_owned(), ), - languages::Language::Python, + &languages::Language::Python, ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); @@ -733,7 +704,7 @@ mod tests { // "03 Oct 2022 11:27:23 -0400".to_owned(), // "05 Oct 2022 23:45:52 +0000".to_owned(), // ), - // languages::Language::C, + // &languages::Language::C, // ); // let after = Utc::now() - now; // println!("time taken: {}", after.num_seconds()); @@ -747,13 +718,13 @@ mod tests { #[cfg(feature = "unstable")] fn go() { let now = Utc::now(); - sleep(Duration::from_secs(2)); + // sleep(Duration::from_secs(2)); println!("go STARTING"); let output = get_function_history( - "empty_test".to_string(), + "empty_test", &FileFilterType::Relative("src/test_functions.go".to_string()), &Filter::None, - languages::Language::Go, + &languages::Language::Go, ); let after = Utc::now() - now; println!("time taken: {}", after.num_seconds()); From 54cda843cb1ec3b94fa882cf64f4d28c35b8fc09 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 9 Nov 2022 15:15:26 -0500 Subject: [PATCH 110/172] removed a lot of unwraps and other panicking code and mmore todos --- git-function-history-lib/src/lib.rs | 65 +++++++++++++---------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 40b48322..a277c59b 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -44,10 +44,7 @@ use languages::{rust, LanguageFilter, PythonFile, RubyFile, RustFile}; use rayon::prelude::{IntoParallelIterator, ParallelIterator}; use git_repository::{prelude::ObjectIdExt, ObjectId}; -use std::{ - error::Error, - process::Command, -}; +use std::{error::Error, process::Command}; // #[cfg(feature = "c_lang")] // use languages::CFile; @@ -143,14 +140,14 @@ pub fn get_function_history( if name.is_empty() { Err("function name is empty")?; } + // TODO: validate filters let repo = git_repository::discover(".")?; let mut tips = vec![]; - let head = repo.head_commit().unwrap(); + let head = repo.head_commit()?; tips.push(head.id); let commit_iter = repo.rev_walk(tips); let commits = commit_iter - .all() - .unwrap() + .all()? .filter_map(|i| match i { Ok(i) => get_item_from_oid_option!(i, &repo, try_into_commit), Err(_) => None, @@ -159,24 +156,24 @@ pub fn get_function_history( let _closest_date = (0, Utc::now()); let commits = commits .iter() - .map(|i| { - let tree = i.tree().unwrap().id; - let time = i.time().unwrap(); + .filter_map(|i| { + let tree = i.tree().ok()?.id; + let time = i.time().ok()?; let time = DateTime::::from_utc( NaiveDateTime::from_timestamp(time.seconds_since_unix_epoch.into(), 0), Utc, ); - let authorinfo = i.author().unwrap(); + let authorinfo = i.author().ok()?; let author = authorinfo.name.to_string(); let email = authorinfo.email.to_string(); - let messages = i.message().unwrap(); + let messages = i.message().ok()?; let mut message = messages.title.to_string(); if let Some(i) = messages.body { message.push_str(i.to_string().as_str()); } let commit = i.id().to_hex().to_string(); let metadata = (message, commit, author, email, time); - (tree, metadata) + Some((tree, metadata)) }) .filter(|(_, metadata)| { match filter { @@ -193,10 +190,10 @@ pub fn get_function_history( let date = metadata.4; let start = DateTime::parse_from_rfc2822(start) .map(|i| i.with_timezone(&Utc)) - .unwrap(); + .expect("failed to parse start date"); let end = DateTime::parse_from_rfc2822(end) .map(|i| i.with_timezone(&Utc)) - .unwrap(); + .expect("failed to parse end date"); start <= date && date <= end } Filter::Author(author) => *author == metadata.2, @@ -211,11 +208,10 @@ pub fn get_function_history( } }) .collect::>(); - let cloned_name = name.clone(); let commits = commits .into_par_iter() .filter_map(|i| { - let tree = sender(i.0, &name, langs, file); + let tree = sender(i.0, name, *langs, file); match tree { Ok(tree) => { if tree.is_empty() { @@ -237,7 +233,7 @@ pub fn get_function_history( if commits.is_empty() { Err("no history found")?; } - let fh = FunctionHistory::new(cloned_name.to_string(), commits); + let fh = FunctionHistory::new(name.to_string(), commits); Ok(fh) } @@ -263,17 +259,13 @@ impl Default for MacroOpts<'_> { fn sender( id: ObjectId, name: &str, - langs: &Language, - file: &FileFilterType - + langs: Language, + file: &FileFilterType, ) -> Result, Box> { - let repo = git_repository::discover(".").unwrap(); - let object = repo.find_object(id).unwrap(); - let tree = object.into_tree(); - let files = traverse_tree(&tree, &repo, name,"", langs, file); - - files - + let repo = git_repository::discover(".")?; + let object = repo.find_object(id)?; + let tree = object.try_into_tree()?; + traverse_tree(&tree, &repo, name, "", langs, file) } fn traverse_tree( @@ -281,14 +273,14 @@ fn traverse_tree( repo: &git_repository::Repository, name: &str, path: &str, - langs: &Language, + langs: Language, filetype: &FileFilterType, ) -> Result, Box> { let treee_iter = tree.iter(); let mut files: Vec<(String, String)> = Vec::new(); let mut ret = Vec::new(); for i in treee_iter { - let i = i.unwrap(); + let i = i?; match &i.mode() { git_object::tree::EntryMode::Tree => { let new = get_item_from!(i.oid(), &repo, try_into_tree); @@ -385,7 +377,7 @@ fn traverse_tree( ret.extend(find_function_in_files_with_commit( files, name.to_string(), - *langs, + langs, )); Ok(ret) @@ -432,8 +424,10 @@ macro_rules! get_function_history { ) }}; } +// TODO: make get_git_dates & get_git_commits use gitoxide or make seperate functions for them #[inline] /// List all the commits date in the git history (in rfc2822 format). +/// requires git to be installed pub fn get_git_dates() -> Result, Box> { let output = Command::new("git") .args(["log", "--pretty=%aD", "--date", "rfc2822"]) @@ -447,6 +441,7 @@ pub fn get_git_dates() -> Result, Box> { } #[inline] /// List all the commit hashes in the git history. +/// requires git to be installed pub fn get_git_commit_hashes() -> Result, Box> { let output = Command::new("git").args(["log", "--pretty=%H"]).output()?; let output = String::from_utf8(output.stdout)?; @@ -461,7 +456,7 @@ fn find_function_in_file_with_commit( file_path: &str, fc: &str, name: &str, - langs: &Language, + langs: Language, ) -> Result> { let file = match langs { Language::Rust => { @@ -528,7 +523,7 @@ fn find_function_in_files_with_commit( #[cfg(not(feature = "parallel"))] let t = files.iter(); t.filter_map(|(file_path, fc)| { - find_function_in_file_with_commit(file_path, fc, &name, &langs).ok() + find_function_in_file_with_commit(file_path, fc, &name, langs).ok() }) .collect() } @@ -540,10 +535,10 @@ trait UnwrapToError { impl UnwrapToError for Option { fn unwrap_to_error_sync(self, message: &str) -> Result> { - self.map_or_else(|| Err(message.to_string().into()), |val| Ok(val)) + self.map_or_else(|| Err(message)?, |val| Ok(val)) } fn unwrap_to_error(self, message: &str) -> Result> { - self.map_or_else(|| Err(message.to_string().into()), |val| Ok(val)) + self.map_or_else(|| Err(message)?, |val| Ok(val)) } } From 48657223efe9cd31d987e1bc07ae9664ea192184 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 9 Nov 2022 16:36:30 -0500 Subject: [PATCH 111/172] made cache deafault fixed bugs when not using paralel --- git-function-history-lib/Cargo.toml | 2 +- git-function-history-lib/src/lib.rs | 21 +++++++++++---------- git-function-history-lib/src/types.rs | 16 ++++++++-------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index bd21c6d6..a76b50e7 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -9,7 +9,7 @@ categories = ["tools", "git"] description = "show function history from git" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["parallel"] +default = ["parallel", "cache"] parallel = ["dep:rayon"] # c_lang = [] # unstable = ["dep:gosyn", "dep:javaparser"] diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index a277c59b..1815c086 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -40,8 +40,8 @@ macro_rules! get_item_from_oid_option { use cached::proc_macro::cached; use chrono::{DateTime, NaiveDateTime, Utc}; use languages::{rust, LanguageFilter, PythonFile, RubyFile, RustFile}; - -use rayon::prelude::{IntoParallelIterator, ParallelIterator}; +#[cfg(feature = "parallel")] +use rayon::prelude::{IntoParallelIterator, ParallelIterator, IntoParallelRefIterator}; use git_repository::{prelude::ObjectIdExt, ObjectId}; use std::{error::Error, process::Command}; @@ -208,9 +208,11 @@ pub fn get_function_history( } }) .collect::>(); - let commits = commits - .into_par_iter() - .filter_map(|i| { + #[cfg(feature = "parallel")] + let commits = commits.into_par_iter(); + #[cfg(not(feature = "parallel"))] + let commits = commits.iter(); + let commits = commits.filter_map(|i| { let tree = sender(i.0, name, *langs, file); match tree { Ok(tree) => { @@ -218,12 +220,12 @@ pub fn get_function_history( None?; } Some(Commit::new( - i.1 .1, + &i.1 .1, tree, &i.1 .4.to_rfc2822(), - i.1 .2, - i.1 .3, - i.1 .0, + &i.1 .2, + &i.1 .3, + &i.1 .0, )) } Err(_) => None, @@ -517,7 +519,6 @@ fn find_function_in_files_with_commit( name: String, langs: Language, ) -> Vec { - use rayon::iter::IntoParallelRefIterator; #[cfg(feature = "parallel")] let t = files.par_iter(); #[cfg(not(feature = "parallel"))] diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index b9112c48..2b984381 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -122,22 +122,22 @@ pub struct Commit { impl Commit { /// Create a new `Commit` with the given `commit_hash`, functions, and date. pub fn new( - commit_hash: String, + commit_hash: &str, files: Vec, date: &str, - author: String, - email: String, - message: String, + author: &str, + email: &str, + message: &str, ) -> Self { Self { - commit_hash, + commit_hash: commit_hash.to_string(), files, date: DateTime::parse_from_rfc2822(date).expect("Failed to parse date"), current_pos: 0, current_iter_pos: 0, - author, - email, - message, + author: author.to_string(), + email: email.to_string(), + message : message.to_string(), } } From da7ef2c43be07e3b9831c19d425f4deb82abf417 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 9 Nov 2022 19:21:46 -0500 Subject: [PATCH 112/172] making lib go faster --- git-function-history-lib/Cargo.toml | 6 +++--- git-function-history-lib/src/lib.rs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index a76b50e7..bcde5a43 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -10,7 +10,7 @@ description = "show function history from git" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] default = ["parallel", "cache"] -parallel = ["dep:rayon"] +parallel = ["dep:rayon", "git-features/parallel"] # c_lang = [] # unstable = ["dep:gosyn", "dep:javaparser"] unstable = ["dep:gosyn"] @@ -30,5 +30,5 @@ gosyn = {version = "0.2.0", optional = true} cfg-if = "1.0.0" cached = {version = "0.40.0", optional = true} gitoxide-core = "0.19.0" -git-repository = { version = "0.27.0", default-features = false } -git-object = "0.22.1" \ No newline at end of file +git-repository = { version = "0.27.0", default-features = false, features = ["max-performance-safe"] } +git-features = { version = "0.23.1", features = ["zlib", "once_cell"] } \ No newline at end of file diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 1815c086..b4bc4b1b 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -43,7 +43,7 @@ use languages::{rust, LanguageFilter, PythonFile, RubyFile, RustFile}; #[cfg(feature = "parallel")] use rayon::prelude::{IntoParallelIterator, ParallelIterator, IntoParallelRefIterator}; -use git_repository::{prelude::ObjectIdExt, ObjectId}; +use git_repository::{prelude::ObjectIdExt, ObjectId, objs}; use std::{error::Error, process::Command}; // #[cfg(feature = "c_lang")] @@ -284,12 +284,12 @@ fn traverse_tree( for i in treee_iter { let i = i?; match &i.mode() { - git_object::tree::EntryMode::Tree => { + objs::tree::EntryMode::Tree => { let new = get_item_from!(i.oid(), &repo, try_into_tree); let path_new = format!("{path}/{}", i.filename()); ret.extend(traverse_tree(&new, repo, name, &path_new, langs, filetype)?); } - git_object::tree::EntryMode::Blob => { + objs::tree::EntryMode::Blob => { let file = format!("{path}/{}", i.filename()); match &filetype { FileFilterType::Relative(ref path) => { @@ -363,7 +363,7 @@ fn traverse_tree( }, } let obh = repo.find_object(i.oid())?; - let objref = git_object::ObjectRef::from_bytes(obh.kind, &obh.data)?; + let objref = objs::ObjectRef::from_bytes(obh.kind, &obh.data)?; let blob = objref.into_blob(); if let Some(blob) = blob { files.push(( From 948d2f8e8156b3da053e241235250d1a26bffd03 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 9 Nov 2022 20:51:57 -0500 Subject: [PATCH 113/172] removing useless no-parelel feature flag --- cargo-function-history/Cargo.toml | 1 - function_history_backend_thread/Cargo.toml | 1 - git-function-history-gui/Cargo.toml | 1 - git-function-history-lib/src/lib.rs | 7 ++++--- git-function-history-lib/src/types.rs | 4 ++-- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/cargo-function-history/Cargo.toml b/cargo-function-history/Cargo.toml index f44647c0..4f0cea34 100644 --- a/cargo-function-history/Cargo.toml +++ b/cargo-function-history/Cargo.toml @@ -13,7 +13,6 @@ description = "cargo frontend for git-function-history" [features] default = ["parallel"] parallel = ["git_function_history/parallel", "function_history_backend_thread/parallel"] -not-parallel = [] # c_lang = ["function_history_backend_thread/c_lang", "git_function_history/c_lang"] unstable = ["function_history_backend_thread/unstable", "git_function_history/unstable"] diff --git a/function_history_backend_thread/Cargo.toml b/function_history_backend_thread/Cargo.toml index 392496e1..3fbfa1b0 100644 --- a/function_history_backend_thread/Cargo.toml +++ b/function_history_backend_thread/Cargo.toml @@ -14,7 +14,6 @@ description = "threading and types for git-function-history" [features] default = ["parallel"] parallel = ["git_function_history/parallel"] -not-parallel = [] # c_lang = ["git_function_history/c_lang"] unstable = ["git_function_history/unstable"] diff --git a/git-function-history-gui/Cargo.toml b/git-function-history-gui/Cargo.toml index 82b482ea..fdc851e2 100644 --- a/git-function-history-gui/Cargo.toml +++ b/git-function-history-gui/Cargo.toml @@ -13,7 +13,6 @@ description = "GUI frontend for git-function-history" [features] default = ["parallel"] parallel = ["git_function_history/parallel", "function_history_backend_thread/parallel"] -not-parallel = [] # c_lang = ["git_function_history/c_lang", "function_history_backend_thread/c_lang"] unstable = ["git_function_history/unstable", "function_history_backend_thread/unstable"] diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index b4bc4b1b..9aa1c127 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -41,9 +41,9 @@ use cached::proc_macro::cached; use chrono::{DateTime, NaiveDateTime, Utc}; use languages::{rust, LanguageFilter, PythonFile, RubyFile, RustFile}; #[cfg(feature = "parallel")] -use rayon::prelude::{IntoParallelIterator, ParallelIterator, IntoParallelRefIterator}; +use rayon::prelude::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator}; -use git_repository::{prelude::ObjectIdExt, ObjectId, objs}; +use git_repository::{objs, prelude::ObjectIdExt, ObjectId}; use std::{error::Error, process::Command}; // #[cfg(feature = "c_lang")] @@ -212,7 +212,8 @@ pub fn get_function_history( let commits = commits.into_par_iter(); #[cfg(not(feature = "parallel"))] let commits = commits.iter(); - let commits = commits.filter_map(|i| { + let commits = commits + .filter_map(|i| { let tree = sender(i.0, name, *langs, file); match tree { Ok(tree) => { diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 2b984381..29f311c6 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -126,7 +126,7 @@ impl Commit { files: Vec, date: &str, author: &str, - email: &str, + email: &str, message: &str, ) -> Self { Self { @@ -137,7 +137,7 @@ impl Commit { current_iter_pos: 0, author: author.to_string(), email: email.to_string(), - message : message.to_string(), + message: message.to_string(), } } From 475e06455fe299c9e1fd1a91159a279d813baa24 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 9 Nov 2022 21:15:10 -0500 Subject: [PATCH 114/172] stopped hardcoding language in gui --- git-function-history-gui/src/lib.rs | 14 ++------------ git-function-history-lib/src/lib.rs | 1 + 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index 55d04cfa..a2c2818c 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -633,17 +633,7 @@ impl eframe::App for MyEguiApp { } _ => {} } - let text = match self.language { - Language::Rust => "Rust", - #[cfg(feature = "c_lang")] - Language::C => "C", - - Language::Python => "Python", - Language::All => "Language", - #[cfg(feature = "unstable")] - Language::Go => "Go", - Language::Ruby => "Ruby", - }; + let text = self.language.to_string(); egui::ComboBox::from_id_source("search_language_combo_box") .selected_text(text) .show_ui(ui, |ui| { @@ -678,7 +668,7 @@ impl eframe::App for MyEguiApp { self.input_buffer.clone(), self.file_type.clone(), self.filter.clone(), - Language::Rust, + self.language.clone(), )) .expect("could not send message in thread"); } diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 9aa1c127..386dfd5b 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -14,6 +14,7 @@ clippy::return_self_not_must_use, clippy::module_name_repetitions )] +/// code and function related language pub mod languages; /// Different types that can extracted from the result of `get_function_history`. pub mod types; From 98f6af8ac98ef243a8e07bdf826d3aa595bf6efa Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 9 Nov 2022 23:10:16 -0500 Subject: [PATCH 115/172] almost done reimplemtning using gitoxide --- git-function-history-gui/src/lib.rs | 2 +- git-function-history-lib/src/lib.rs | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index a2c2818c..1a1aaac6 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -668,7 +668,7 @@ impl eframe::App for MyEguiApp { self.input_buffer.clone(), self.file_type.clone(), self.filter.clone(), - self.language.clone(), + self.language, )) .expect("could not send message in thread"); } diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 386dfd5b..85a3fef9 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -142,6 +142,7 @@ pub fn get_function_history( Err("function name is empty")?; } // TODO: validate filters + // if filter is date list all the dates and find the one that is closest to the date set that to closest_date and when using the first filter check if the date of the commit is equal to the closest_date let repo = git_repository::discover(".")?; let mut tips = vec![]; let head = repo.head_commit()?; @@ -154,7 +155,7 @@ pub fn get_function_history( Err(_) => None, }) .collect::>(); - let _closest_date = (0, Utc::now()); + let closest_date = Utc::now(); let commits = commits .iter() .filter_map(|i| { @@ -179,12 +180,13 @@ pub fn get_function_history( .filter(|(_, metadata)| { match filter { Filter::CommitHash(hash) => *hash == metadata.1, - Filter::Date(_date) => { + Filter::Date(date) => { // TODO: fix this - // if closest_date - // let date = date.parse::>().unwrap(); - // let cmp = DateTime::::from_utc(NaiveDateTime::from_timestamp(metadata.4.seconds_since_unix_epoch.into(), 0), Utc); - false + closest_date == match date.parse::>() { + Ok(i) => i, + Err(_) => return false, + } + } Filter::DateRange(start, end) => { // let date = metadata.4.seconds_since_unix_epoch; From 4281ba3d13fcb84a012571b1aba43c2b830d02fa Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 10 Nov 2022 17:01:34 -0500 Subject: [PATCH 116/172] date filter works, now just need to do other filter vaildation and the push back into other_language_support --- git-function-history-lib/src/lib.rs | 88 +++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 12 deletions(-) diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 85a3fef9..9d27e328 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -12,7 +12,8 @@ clippy::similar_names, clippy::missing_errors_doc, clippy::return_self_not_must_use, - clippy::module_name_repetitions + clippy::module_name_repetitions, + clippy::multiple_crate_versions )] /// code and function related language pub mod languages; @@ -45,7 +46,7 @@ use languages::{rust, LanguageFilter, PythonFile, RubyFile, RustFile}; use rayon::prelude::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator}; use git_repository::{objs, prelude::ObjectIdExt, ObjectId}; -use std::{error::Error, process::Command}; +use std::{error::Error, ops::Sub, process::Command}; // #[cfg(feature = "c_lang")] // use languages::CFile; @@ -155,7 +156,21 @@ pub fn get_function_history( Err(_) => None, }) .collect::>(); - let closest_date = Utc::now(); + // find the closest date by using get_git_dates_commits_oxide + let closest_date = if let Filter::Date(date) = filter { + let date = DateTime::parse_from_rfc2822(date)?.with_timezone(&Utc); + let date_list = get_git_dates_commits_oxide()?; + date_list + .iter() + .min_by_key(|elem| { + elem.0.sub(date).num_seconds().abs() + // elem.0.signed_duration_since(date) + }) + .map(|elem| elem.1.clone()) + .unwrap_to_error_sync("no commits found")? + } else { + String::new() + }; let commits = commits .iter() .filter_map(|i| { @@ -180,14 +195,7 @@ pub fn get_function_history( .filter(|(_, metadata)| { match filter { Filter::CommitHash(hash) => *hash == metadata.1, - Filter::Date(date) => { - // TODO: fix this - closest_date == match date.parse::>() { - Ok(i) => i, - Err(_) => return false, - } - - } + Filter::Date(_) => metadata.1 == closest_date, Filter::DateRange(start, end) => { // let date = metadata.4.seconds_since_unix_epoch; let date = metadata.4; @@ -445,6 +453,42 @@ pub fn get_git_dates() -> Result, Box> { .collect::>(); Ok(output) } + +pub fn get_git_dates_commits_oxide( +) -> Result, String)>, Box> { + let repo = git_repository::discover(".")?; + // let mut dates = Vec::new(); + let mut tips = vec![]; + let head = repo.head_commit()?; + tips.push(head.id); + let commit_iter = repo.rev_walk(tips); + let commits = commit_iter + .all()? + .filter_map(|i| match i { + Ok(i) => get_item_from_oid_option!(i, &repo, try_into_commit).map(|i| { + ( + i.time() + .map(|x| { + // println!("{:?}", x); + DateTime::::from_utc( + NaiveDateTime::from_timestamp(x.seconds_since_unix_epoch.into(), 0), + Utc, + ) + // NaiveDateTime::from_timestamp(x.seconds_since_unix_epoch.into(), 0) + }) + .ok(), + i.id.to_string(), + ) + }), + Err(_) => None, + }) + .filter_map(|i| match i { + (Some(i), j) => Some((i, j)), + _ => None, + }); + Ok(commits.collect()) +} + #[inline] /// List all the commit hashes in the git history. /// requires git to be installed @@ -620,7 +664,7 @@ mod tests { .contains("file is not a rust file")); } #[test] - fn test_date() { + fn test_date_range() { let now = Utc::now(); let output = get_function_history( "empty_test", @@ -642,6 +686,26 @@ mod tests { assert!(output.is_ok()); } + #[test] + fn tet_date() { + let now = Utc::now(); + let output = get_function_history( + "empty_test", + &FileFilterType::None, + &Filter::Date("27 Sep 2022 00:27:23 -0400".to_owned()), + &languages::Language::Rust, + ); + let after = Utc::now() - now; + println!("time taken: {}", after.num_seconds()); + match &output { + Ok(functions) => { + println!("{functions}"); + } + Err(e) => println!("-{e}-"), + } + assert!(output.is_ok()); + } + #[test] fn expensive_tes() { let now = Utc::now(); From 60a435904363b857bbd342754ec9442b354c44d6 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 10 Nov 2022 20:22:21 -0500 Subject: [PATCH 117/172] update workflows for no c_lang --- .github/workflows/cargo_clippy_lib.yml | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/workflows/cargo_clippy_lib.yml b/.github/workflows/cargo_clippy_lib.yml index 9abbe1a1..bb777de2 100644 --- a/.github/workflows/cargo_clippy_lib.yml +++ b/.github/workflows/cargo_clippy_lib.yml @@ -15,7 +15,8 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} toolchain: nightly - args: -p git_function_history --features unstable --features c_lang + args: -p git_function_history --features unstable + # --features c_lang nightly-clang-test: runs-on: ubuntu-latest steps: @@ -27,17 +28,18 @@ jobs: override: true - name: test run: | - cargo +nightly test -p git_function_history --features unstable --features c_lang -- --nocapture + cargo +nightly test -p git_function_history --features unstable -- --nocapture + # --features c_lang -- --nocapture - test-clang: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: setup rust - uses: dtolnay/rust-toolchain@stable - - name: test - run: | - cargo test -p git_function_history --features c_lang -- --nocapture + # test-clang: + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v3 + # - name: setup rust + # uses: dtolnay/rust-toolchain@stable + # - name: test + # run: | + # cargo test -p git_function_history --features c_lang -- --nocapture test: runs-on: ubuntu-latest From 6b8bfaccb18691fe82ade43f81d600cf72a4815d Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 10 Nov 2022 20:33:26 -0500 Subject: [PATCH 118/172] debbbuging why date range no work in ci --- .github/workflows/cargo_clippy_lib.yml | 25 ++++++++++++------------- .github/workflows/chanelog.yaml | 2 +- git-function-history-lib/src/lib.rs | 1 + 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/cargo_clippy_lib.yml b/.github/workflows/cargo_clippy_lib.yml index bb777de2..9ba077ec 100644 --- a/.github/workflows/cargo_clippy_lib.yml +++ b/.github/workflows/cargo_clippy_lib.yml @@ -17,19 +17,18 @@ jobs: toolchain: nightly args: -p git_function_history --features unstable # --features c_lang - nightly-clang-test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: setup rust - uses: dtolnay/rust-toolchain@stable - with: - toolchain: nightly - override: true - - name: test - run: | - cargo +nightly test -p git_function_history --features unstable -- --nocapture - # --features c_lang -- --nocapture + # nightly-clang-test: + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v3 + # - name: setup rust + # uses: dtolnay/rust-toolchain@stable + # with: + # toolchain: nightly + # override: true + # - name: test + # run: | + # cargo +nightly test -p git_function_history --features unstable --features c_lang -- --nocapture # test-clang: # runs-on: ubuntu-latest diff --git a/.github/workflows/chanelog.yaml b/.github/workflows/chanelog.yaml index d1c96f64..e5865d04 100644 --- a/.github/workflows/chanelog.yaml +++ b/.github/workflows/chanelog.yaml @@ -1,4 +1,4 @@ -name: Action Test +name: changelog-generator on: [push] diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 9d27e328..ba2bdb77 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -205,6 +205,7 @@ pub fn get_function_history( let end = DateTime::parse_from_rfc2822(end) .map(|i| i.with_timezone(&Utc)) .expect("failed to parse end date"); + println!("start: {:?}, end: {:?}, date: {:?}", start, end, date); start <= date && date <= end } Filter::Author(author) => *author == metadata.2, From 8678985ed07fa1121b7a207c4adff821fb59a784 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 10 Nov 2022 20:33:40 -0500 Subject: [PATCH 119/172] ooops this too --- git-function-history-lib/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index ba2bdb77..85d432d3 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -206,6 +206,7 @@ pub fn get_function_history( .map(|i| i.with_timezone(&Utc)) .expect("failed to parse end date"); println!("start: {:?}, end: {:?}, date: {:?}", start, end, date); + println!("IS BETWEEN: {}", start <= date && date <= end); start <= date && date <= end } Filter::Author(author) => *author == metadata.2, From 0b3aaecf85f1ef0ab2db4fcd1e7be6d6aede8d98 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 10 Nov 2022 21:17:50 -0500 Subject: [PATCH 120/172] added filter validation just going to see if theres any other problems before the pr back into other_language_support --- git-function-history-lib/src/languages/mod.rs | 32 +++++++++++ git-function-history-lib/src/lib.rs | 55 +++++++++++-------- 2 files changed, 65 insertions(+), 22 deletions(-) diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index b48a76a8..11410129 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -59,6 +59,38 @@ impl Language { _ => Err(format!("Unknown language: {s}"))?, } } + + pub fn get_names(&self) -> &str { + match self { + Self::Python => "python", + Self::Rust => "rust", + // #[cfg(feature = "c_lang")] + // Language::C => "c", + #[cfg(feature = "unstable")] + Self::Go => "go", + Self::Ruby => "ruby", + #[cfg(feature = "unstable")] + Self::All => "python, rust, go, or ruby", + #[cfg(not(feature = "unstable"))] + Language::All => "python, rust, or ruby", + } + } + + pub fn get_file_endings(&self) -> &[&str] { + match self { + Self::Python => &["py"], + Self::Rust => &["rs"], + // #[cfg(feature = "c_lang")] + // Language::C => &["c", "h"], + #[cfg(feature = "unstable")] + Self::Go => &["go"], + Self::Ruby => &["rb"], + #[cfg(feature = "unstable")] + Self::All => &["py", "rs", "go", "rb"], + #[cfg(not(feature = "unstable"))] + Language::All => &["py", "rs", "rb"], + } + } } impl fmt::Display for Language { diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 85d432d3..e73426ea 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -64,7 +64,7 @@ pub use { pub enum FileFilterType { /// When you have a absolute path to a file. Absolute(String), - /// When you have a relative path to a file and or want to find look in all files match a name. + /// When you have a relative path to a file and or want to find look in all files match a name (aka ends_with). Relative(String), /// When you want to filter only files in a specific directory Directory(String), @@ -128,7 +128,7 @@ pub enum Filter { /// /// ``` /// use git_function_history::{get_function_history, Filter, FileFilterType, Language}; -/// let t = get_function_history("empty_test", &FileFilterType::Absolute("src/test_functions.rs".to_string()), &Filter::None, language::Rust).unwrap(); +/// let t = get_function_history("empty_test", &FileFilterType::Absolute("src/test_functions.rs".to_string()), &Filter::None, &Language::Rust).unwrap(); /// ``` #[allow(clippy::too_many_lines)] // TODO: split this function into smaller functions @@ -157,20 +157,37 @@ pub fn get_function_history( }) .collect::>(); // find the closest date by using get_git_dates_commits_oxide - let closest_date = if let Filter::Date(date) = filter { - let date = DateTime::parse_from_rfc2822(date)?.with_timezone(&Utc); - let date_list = get_git_dates_commits_oxide()?; - date_list - .iter() - .min_by_key(|elem| { - elem.0.sub(date).num_seconds().abs() - // elem.0.signed_duration_since(date) - }) - .map(|elem| elem.1.clone()) - .unwrap_to_error_sync("no commits found")? - } else { - String::new() + let closest_date = match filter { + Filter::Date(date) => { + let date = DateTime::parse_from_rfc2822(date)?.with_timezone(&Utc); + let date_list = get_git_dates_commits_oxide()?; + date_list + .iter() + .min_by_key(|elem| { + elem.0.sub(date).num_seconds().abs() + // elem.0.signed_duration_since(date) + }) + .map(|elem| elem.1.clone()) + .unwrap_to_error_sync("no commits found")? + } + Filter::Author(_) + | Filter::AuthorEmail(_) + | Filter::Message(_) + | Filter::DateRange(..) + | Filter::None + | Filter::CommitHash(_) => String::new(), + _ => Err("invalid filter")?, }; + match file { + FileFilterType::Absolute(file) | FileFilterType::Relative(file) => { + // vaildate that the file makes sense with language + let is_supported = langs.get_file_endings().iter().any(|i| file.ends_with(i)); + if !is_supported { + Err(format!("file {file} is not a {} file", langs.get_names()))?; + } + } + FileFilterType::Directory(_) | FileFilterType::None => {} + } let commits = commits .iter() .filter_map(|i| { @@ -205,8 +222,6 @@ pub fn get_function_history( let end = DateTime::parse_from_rfc2822(end) .map(|i| i.with_timezone(&Utc)) .expect("failed to parse end date"); - println!("start: {:?}, end: {:?}, date: {:?}", start, end, date); - println!("IS BETWEEN: {}", start <= date && date <= end); start <= date && date <= end } Filter::Author(author) => *author == metadata.2, @@ -380,16 +395,12 @@ fn traverse_tree( let objref = objs::ObjectRef::from_bytes(obh.kind, &obh.data)?; let blob = objref.into_blob(); if let Some(blob) = blob { - files.push(( - i.filename().to_string(), - String::from_utf8_lossy(blob.data).to_string(), - )); + files.push((file, String::from_utf8_lossy(blob.data).to_string())); } } _ => {} } } - ret.extend(find_function_in_files_with_commit( files, name.to_string(), From 8774d41f12d6ca2666eb29e19ab70f3df9588735 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 10 Nov 2022 22:34:46 -0500 Subject: [PATCH 121/172] fixed not_rust_file test --- git-function-history-lib/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index e73426ea..da7ecd06 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -671,10 +671,11 @@ mod tests { &languages::Language::Rust, ); assert!(output.is_err()); + println!("{}", (&output).as_ref().unwrap_err()); assert!(output .unwrap_err() .to_string() - .contains("file is not a rust file")); + .contains("is not a rust file")); } #[test] fn test_date_range() { From 9856e513e33cf19d23c06e443f5286aa61a700eb Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Fri, 11 Nov 2022 15:53:20 -0500 Subject: [PATCH 122/172] I think werer ready to merge back into other_languge_support --- git-function-history-lib/src/languages/mod.rs | 10 +++++----- git-function-history-lib/src/languages/rust.rs | 1 - git-function-history-lib/src/lib.rs | 9 ++++----- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 11410129..6132b434 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -60,7 +60,7 @@ impl Language { } } - pub fn get_names(&self) -> &str { + pub const fn get_names(&self) -> &str { match self { Self::Python => "python", Self::Rust => "rust", @@ -76,9 +76,9 @@ impl Language { } } - pub fn get_file_endings(&self) -> &[&str] { + pub const fn get_file_endings(&self) -> &[&str] { match self { - Self::Python => &["py"], + Self::Python => &["py", "pyw"], Self::Rust => &["rs"], // #[cfg(feature = "c_lang")] // Language::C => &["c", "h"], @@ -86,9 +86,9 @@ impl Language { Self::Go => &["go"], Self::Ruby => &["rb"], #[cfg(feature = "unstable")] - Self::All => &["py", "rs", "go", "rb"], + Self::All => &["py", "pyw", "rs", "go", "rb"], #[cfg(not(feature = "unstable"))] - Language::All => &["py", "rs", "rb"], + Language::All => &["py", "pyw", "rs", "rb"], } } } diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 0768db19..8c1e0fe4 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -198,7 +198,6 @@ impl fmt::Display for BlockType { } } -#[allow(clippy::too_many_lines)] // TODO: split this function into smaller functions pub(crate) fn find_function_in_file( file_contents: &str, diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index da7ecd06..642d765e 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -13,7 +13,8 @@ clippy::missing_errors_doc, clippy::return_self_not_must_use, clippy::module_name_repetitions, - clippy::multiple_crate_versions + clippy::multiple_crate_versions, + clippy::too_many_lines )] /// code and function related language pub mod languages; @@ -130,7 +131,6 @@ pub enum Filter { /// use git_function_history::{get_function_history, Filter, FileFilterType, Language}; /// let t = get_function_history("empty_test", &FileFilterType::Absolute("src/test_functions.rs".to_string()), &Filter::None, &Language::Rust).unwrap(); /// ``` -#[allow(clippy::too_many_lines)] // TODO: split this function into smaller functions pub fn get_function_history( name: &str, @@ -142,7 +142,6 @@ pub fn get_function_history( if name.is_empty() { Err("function name is empty")?; } - // TODO: validate filters // if filter is date list all the dates and find the one that is closest to the date set that to closest_date and when using the first filter check if the date of the commit is equal to the closest_date let repo = git_repository::discover(".")?; let mut tips = vec![]; @@ -554,7 +553,7 @@ fn find_function_in_file_with_commit( // let functions = languages::c::find_function_in_file(fc, name)?; // FileType::C(CFile::new(file_path.to_string(), functions)) // } - Some("py") => { + Some("py" | "pyw") => { let functions = languages::python::find_function_in_file(fc, name)?; FileType::Python(PythonFile::new(file_path.to_string(), functions)) } @@ -671,7 +670,7 @@ mod tests { &languages::Language::Rust, ); assert!(output.is_err()); - println!("{}", (&output).as_ref().unwrap_err()); + println!("{}", output.as_ref().unwrap_err()); assert!(output .unwrap_err() .to_string() From 36573eebc8d6cf2b69478039531640ac1e2854e5 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Fri, 11 Nov 2022 16:20:55 -0500 Subject: [PATCH 123/172] made a function that gets git info instead of having one for commits one for dates etc --- function_history_backend_thread/src/lib.rs | 45 ++++----- git-function-history-lib/src/lib.rs | 102 +++++++++------------ 2 files changed, 68 insertions(+), 79 deletions(-) diff --git a/function_history_backend_thread/src/lib.rs b/function_history_backend_thread/src/lib.rs index bbb98728..ec548f79 100644 --- a/function_history_backend_thread/src/lib.rs +++ b/function_history_backend_thread/src/lib.rs @@ -39,35 +39,36 @@ pub fn command_thread( log::info!("list"); } match list_type { - ListType::Commits => { - match git_function_history::get_git_commit_hashes() { - Ok(commits) => { - if log { - log::info!("found {} commits", commits.len()); - } - ( - CommandResult::String(commits), - Status::Ok(Some(format!( - "Found commits dates took {}s", - now.elapsed().as_secs() - ))), - ) + ListType::Commits => match git_function_history::get_git_info() { + Ok(commits) => { + if log { + log::info!("found {} commits", commits.len()); } - Err(err) => ( - CommandResult::None, - Status::Error(format!( - "Error getting commits: {} took {}s", - err, + let commits = + commits.iter().map(|c| c.hash.to_string()).collect(); + ( + CommandResult::String(commits), + Status::Ok(Some(format!( + "Found commits dates took {}s", now.elapsed().as_secs() - )), - ), + ))), + ) } - } - ListType::Dates => match git_function_history::get_git_dates() { + Err(err) => ( + CommandResult::None, + Status::Error(format!( + "Error getting commits: {} took {}s", + err, + now.elapsed().as_secs() + )), + ), + }, + ListType::Dates => match git_function_history::get_git_info() { Ok(dates) => { if log { log::info!("found {} dates", dates.len()); } + let dates = dates.iter().map(|d| d.date.to_rfc2822()).collect(); ( CommandResult::String(dates), Status::Ok(Some(format!( diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 642d765e..2eb39480 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -47,7 +47,7 @@ use languages::{rust, LanguageFilter, PythonFile, RubyFile, RustFile}; use rayon::prelude::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator}; use git_repository::{objs, prelude::ObjectIdExt, ObjectId}; -use std::{error::Error, ops::Sub, process::Command}; +use std::{error::Error, ops::Sub}; // #[cfg(feature = "c_lang")] // use languages::CFile; @@ -159,14 +159,14 @@ pub fn get_function_history( let closest_date = match filter { Filter::Date(date) => { let date = DateTime::parse_from_rfc2822(date)?.with_timezone(&Utc); - let date_list = get_git_dates_commits_oxide()?; + let date_list = get_git_info()?; date_list .iter() .min_by_key(|elem| { - elem.0.sub(date).num_seconds().abs() + elem.date.sub(date).num_seconds().abs() // elem.0.signed_duration_since(date) }) - .map(|elem| elem.1.clone()) + .map(|elem| elem.hash.clone()) .unwrap_to_error_sync("no commits found")? } Filter::Author(_) @@ -450,68 +450,56 @@ macro_rules! get_function_history { ) }}; } -// TODO: make get_git_dates & get_git_commits use gitoxide or make seperate functions for them -#[inline] -/// List all the commits date in the git history (in rfc2822 format). -/// requires git to be installed -pub fn get_git_dates() -> Result, Box> { - let output = Command::new("git") - .args(["log", "--pretty=%aD", "--date", "rfc2822"]) - .output()?; - let output = String::from_utf8(output.stdout)?; - let output = output - .split('\n') - .map(std::string::ToString::to_string) - .collect::>(); - Ok(output) -} -pub fn get_git_dates_commits_oxide( -) -> Result, String)>, Box> { +pub fn get_git_info() -> Result, Box> { let repo = git_repository::discover(".")?; - // let mut dates = Vec::new(); let mut tips = vec![]; let head = repo.head_commit()?; tips.push(head.id); let commit_iter = repo.rev_walk(tips); - let commits = commit_iter - .all()? - .filter_map(|i| match i { - Ok(i) => get_item_from_oid_option!(i, &repo, try_into_commit).map(|i| { - ( - i.time() - .map(|x| { - // println!("{:?}", x); - DateTime::::from_utc( - NaiveDateTime::from_timestamp(x.seconds_since_unix_epoch.into(), 0), - Utc, - ) - // NaiveDateTime::from_timestamp(x.seconds_since_unix_epoch.into(), 0) - }) - .ok(), - i.id.to_string(), - ) - }), - Err(_) => None, - }) - .filter_map(|i| match i { - (Some(i), j) => Some((i, j)), - _ => None, - }); + let commits = commit_iter.all()?.filter_map(|i| match i { + Ok(i) => get_item_from_oid_option!(i, &repo, try_into_commit).map(|i| { + let author = match i.author() { + Ok(author) => author, + Err(_) => return None, + }; + let message = match i.message() { + Ok(message) => message, + Err(_) => return None, + }; + let mut msg = message.title.to_string(); + if let Some(msg_body) = message.body { + msg.push_str(&msg_body.to_string()); + } + + Some(CommitInfo { + date: match i.time().map(|x| { + DateTime::::from_utc( + NaiveDateTime::from_timestamp(x.seconds_since_unix_epoch.into(), 0), + Utc, + ) + }) { + Ok(i) => i, + Err(_) => return None, + }, + hash: i.id.to_string(), + author_email: author.email.to_string(), + author: author.name.to_string(), + message: msg, + }) + }), + Err(_) => None, + }); + let commits = commits.flatten(); Ok(commits.collect()) } -#[inline] -/// List all the commit hashes in the git history. -/// requires git to be installed -pub fn get_git_commit_hashes() -> Result, Box> { - let output = Command::new("git").args(["log", "--pretty=%H"]).output()?; - let output = String::from_utf8(output.stdout)?; - let output = output - .split('\n') - .map(std::string::ToString::to_string) - .collect::>(); - Ok(output) +pub struct CommitInfo { + pub date: DateTime, + pub hash: String, + pub message: String, + pub author: String, + pub author_email: String, } fn find_function_in_file_with_commit( From 8ee057716708e9df7de6559d7f2dbbdc26a30d98 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 13 Nov 2022 18:53:14 -0500 Subject: [PATCH 124/172] switching to using locatation.End_line and stop using mem::swap to save lcoation --- TODO.md | 2 +- git-function-history-lib/Cargo.toml | 4 +- git-function-history-lib/src/languages/mod.rs | 2 +- .../src/languages/python.rs | 199 ++++-------------- .../src/test_functions.py | 14 +- 5 files changed, 58 insertions(+), 163 deletions(-) diff --git a/TODO.md b/TODO.md index 135eaf12..faf8ac3d 100644 --- a/TODO.md +++ b/TODO.md @@ -42,4 +42,4 @@ - [ ] make list command a table wiht rows and columns for date, commit, author, message, etc - [ ] (possibly) use tree sitter to provide syntax highlighting - lib: - - [ ] possibly stop using Commmad::new("git") and use https://crates.io/crates/git_rs OR https://crates.io/crates/rs-git-lib OR https://crates.io/crates/gitoxide, to imporve performance with program compibilty assistant sevice on windows + - [x] possibly stop using Commmad::new("git") and use https://crates.io/crates/git_rs OR https://crates.io/crates/rs-git-lib OR https://crates.io/crates/gitoxide, to imporve performance with program compibilty assistant sevice on windows diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index bcde5a43..6c649de9 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -20,9 +20,9 @@ cache = ["dep:cached"] chrono = "0.4.22" ra_ap_syntax = "0.0.138" rayon = { version = "1.5.3", optional = true } -rustpython-parser = "0.1.2" +# rustpython-parser = "0.1.2" # for end_lines but can't be publsihed b/c git depenency -# rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "77b821a1941019fe34f73ce17cea013ae1b98fd0" } +rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb" } lib-ruby-parser = "3.0.12" gosyn = {version = "0.2.0", optional = true} # can't be published b/c git dependency diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 6132b434..539a6fb8 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -4,7 +4,6 @@ use std::{ fmt::{self, Display}, }; // TODO: lisp/scheme js, java?(https://github.com/tanin47/javaparser.rs) php?(https://docs.rs/tagua-parser/0.1.0/tagua_parser/) -// TODO: make a macro for generating filters use self::{python::PythonFunction, ruby::RubyFunction, rust::RustFunction}; // #[cfg(feature = "c_lang")] @@ -313,6 +312,7 @@ mod lang_tests { Ok(hist) => { for i in hist { println!("{}", i); + println!("{:?}", i); } } Err(e) => { diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index ee46e0fc..e0a13002 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -1,6 +1,5 @@ use rustpython_parser::{ - ast::{Located, StatementType}, - location::Location, + ast::{Located, Location, StmtKind}, parser, }; use std::collections::VecDeque; @@ -30,7 +29,7 @@ use super::FunctionTrait; pub struct PythonFunction { pub(crate) name: String, pub(crate) body: String, - // parameters: Params, + /// parameters: Params, pub(crate) parameters: Vec, pub(crate) parent: Vec, pub(crate) decorators: Vec, @@ -57,13 +56,13 @@ impl fmt::Display for PythonFunction { } } -// #[derive(Debug, Clone)] -// pub struct Params { -// args: Vec, -// kwargs: Vec, -// varargs: Option, -// varkwargs: Option, -// } +/// #[derive(Debug, Clone)] +/// pub struct Params { +/// args: Vec, +/// kwargs: Vec, +/// varargs: Option, +/// varkwargs: Option, +/// } #[derive(Debug, Clone)] pub struct Class { pub(crate) name: String, @@ -80,7 +79,7 @@ pub struct PythonParentFunction { pub(crate) lines: (usize, usize), pub(crate) parameters: Vec, pub(crate) decorators: Vec, - // pub(crate) class: Option, + /// pub(crate) class: Option, pub(crate) returns: Option, } @@ -88,14 +87,13 @@ pub(crate) fn find_function_in_file( file_contents: &str, name: &str, ) -> Result, Box> { - let ast = parser::parse_program(file_contents)?; + let ast = parser::parse_program(file_contents, "")?; let mut functions = vec![]; - let mut last = None; - if ast.statements.is_empty() { + if ast.is_empty() { return Err("No code found")?; } - let mut new_ast = VecDeque::from(ast.statements); + let mut new_ast = VecDeque::from(ast); loop { if new_ast.is_empty() { break; @@ -103,8 +101,7 @@ pub(crate) fn find_function_in_file( let stmt = new_ast .pop_front() .unwrap_to_error("could not get statement")?; - let next = new_ast.front(); - get_functions(stmt, next, &mut functions, name, &mut last, &mut None); + get_functions(stmt, &mut functions, name); } let mut starts = file_contents .match_indices('\n') @@ -117,30 +114,17 @@ pub(crate) fn find_function_in_file( .enumerate() .collect::>(); let mut new = Vec::new(); - for mut func in functions { - if func.1 .0 == func.1 .1 { - // get the last line of the file - let last_line = file_contents - .lines() - .last() - .unwrap_to_error("could not get last line")?; - let row = file_contents.lines().count(); - let column = last_line.len(); - let end = Location::new(row, column); - func.1 .1 = end; - } - // get the function body based on the location + for func in functions { let start = func.1 .0.row(); let end = func.1 .1.row(); let start = map[&(start - 1)]; let end = map[&(end - 1)]; - if let StatementType::FunctionDef { + if let StmtKind::FunctionDef { name, args, decorator_list, returns, - is_async: _, .. } = func.0 { @@ -157,12 +141,12 @@ pub(crate) fn find_function_in_file( .collect::(); let new_func = PythonFunction { name: name.to_string(), - returns: returns.as_ref().map(|x| x.name().to_string()), - parameters: args.args.iter().map(|x| x.arg.to_string()).collect(), + returns: returns.as_ref().map(|x| x.node.name().to_string()), + parameters: args.args.iter().map(|x| x.node.arg.to_string()).collect(), parent: vec![], decorators: decorator_list .iter() - .map(|x| x.name().to_string()) + .map(|x| x.node.name().to_string()) .collect(), class: None, body, @@ -178,11 +162,9 @@ pub(crate) fn find_function_in_file( } #[inline] fn fun_name1( - body: Vec>, - functions: &mut Vec<(StatementType, (Location, Location))>, + body: Vec>, + functions: &mut Vec<(StmtKind, (Location, Location))>, lookup_name: &str, - last_found_fn: &mut Option<(StatementType, Location)>, - other_last_found_fn: &mut Option<(StatementType, Location)>, ) { let mut new_ast = VecDeque::from(body); loop { @@ -190,135 +172,46 @@ fn fun_name1( break; } let stmt = new_ast.pop_front().expect("could not get statement"); - let next = new_ast.front(); - get_functions( - stmt, - next, - functions, - lookup_name, - last_found_fn, - other_last_found_fn, - ); - } -} -#[inline] -fn fun_name( - other_last_found_fn: &mut Option<(StatementType, Location)>, - last_found_fn: &mut Option<(StatementType, Location)>, - functions: &mut Vec<(StatementType, (Location, Location))>, - stmt: Location, -) { - std::mem::swap(other_last_found_fn, last_found_fn); - let mut other = None; - std::mem::swap(&mut other, other_last_found_fn); - if let Some(body) = other { - functions.push((body.0, (body.1, stmt))); + get_functions(stmt, functions, lookup_name); } } -fn get_functions<'a>( - // TODO: get parent functions and classes - stmt: Located, - next_stmt: Option<&Located>, - functions: &mut Vec<(StatementType, (Location, Location))>, +fn get_functions( + stmt: Located, + + functions: &mut Vec<(StmtKind, (Location, Location))>, lookup_name: &str, - last_found_fn: &'a mut Option<(StatementType, Location)>, - other_last_found_fn: &'a mut Option<(StatementType, Location)>, ) { match stmt.node { - StatementType::FunctionDef { ref name, .. } if name == lookup_name => { - if let Some(ref mut last) = last_found_fn { - let mut new = (stmt.node, stmt.location); - std::mem::swap(last, &mut new); - functions.push((new.0, (new.1, stmt.location))); - } else if next_stmt.is_none() { - functions.push((stmt.node, (stmt.location, stmt.location))); - } else { - *last_found_fn = Some((stmt.node, stmt.location)); - } - // let r = Range::from_located(&stmt); - // println!("Found function {} at {:?}", name, r); - } + StmtKind::FunctionDef { ref name, .. } if name == lookup_name => if let Some(end) = stmt.end_location { + functions.push((stmt.node, (stmt.location, end))); + }, - StatementType::If { body, orelse, .. } - | StatementType::While { body, orelse, .. } - | StatementType::For { body, orelse, .. } => { - fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); - fun_name1( - body, - functions, - lookup_name, - last_found_fn, - other_last_found_fn, - ); - if let Some(stmts) = orelse { - fun_name1( - stmts, - functions, - lookup_name, - last_found_fn, - other_last_found_fn, - ); - } + StmtKind::If { body, orelse, .. } + | StmtKind::While { body, orelse, .. } + | StmtKind::For { body, orelse, .. } => { + fun_name1(body, functions, lookup_name); + + fun_name1(orelse, functions, lookup_name); } - StatementType::FunctionDef { body, .. } - | StatementType::ClassDef { body, .. } - | StatementType::With { body, .. } => { - fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); - fun_name1( - body, - functions, - lookup_name, - last_found_fn, - other_last_found_fn, - ); + StmtKind::FunctionDef { body, .. } + | StmtKind::ClassDef { body, .. } + | StmtKind::With { body, .. } => { + fun_name1(body, functions, lookup_name); } - StatementType::Try { + StmtKind::Try { body, - handlers, orelse, finalbody, + .. } => { - fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); - fun_name1( - body, - functions, - lookup_name, - last_found_fn, - other_last_found_fn, - ); - for handler in handlers { - fun_name1( - handler.body, - functions, - lookup_name, - last_found_fn, - other_last_found_fn, - ); - } + fun_name1(body, functions, lookup_name); - if let Some(stmts) = orelse { - fun_name1( - stmts, - functions, - lookup_name, - last_found_fn, - other_last_found_fn, - ); - } - if let Some(stmts) = finalbody { - fun_name1( - stmts, - functions, - lookup_name, - last_found_fn, - other_last_found_fn, - ); - } - } - _ => { - fun_name(other_last_found_fn, last_found_fn, functions, stmt.location); + fun_name1(orelse, functions, lookup_name); + + fun_name1(finalbody, functions, lookup_name); } + _ => {} } } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/git-function-history-lib/src/test_functions.py b/git-function-history-lib/src/test_functions.py index 92023c4a..679c1804 100644 --- a/git-function-history-lib/src/test_functions.py +++ b/git-function-history-lib/src/test_functions.py @@ -1,16 +1,18 @@ from ctypes.wintypes import PINT - PINT = 1 -def empty_test(): - print("This is an empty test") +# def empty_test(): +# print("This is an empty test") -def test_with_assert(): +def test_with_assert(n): + @assert_that("This is a test with an assert") + def empty_test(t): + return t == n assert True passing_test = test_with_assert - -def empty_test(): +@def_test +def empty_test(n: int) -> list: """This is an empty test with a docstring""" pass From 787e75a2974d8619c7937bb64225c821d58cbcf6 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 13 Nov 2022 19:28:45 -0500 Subject: [PATCH 125/172] more stuff --- .../src/languages/python.rs | 105 ++++++++++++------ 1 file changed, 71 insertions(+), 34 deletions(-) diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index e0a13002..02a3b0d3 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -33,7 +33,7 @@ pub struct PythonFunction { pub(crate) parameters: Vec, pub(crate) parent: Vec, pub(crate) decorators: Vec, - pub(crate) class: Option, + pub(crate) class: Option, pub(crate) lines: (usize, usize), pub(crate) returns: Option, } @@ -64,7 +64,7 @@ impl fmt::Display for PythonFunction { /// varkwargs: Option, /// } #[derive(Debug, Clone)] -pub struct Class { +pub struct PythonClass { pub(crate) name: String, pub(crate) top: String, pub(crate) bottom: String, @@ -93,16 +93,7 @@ pub(crate) fn find_function_in_file( if ast.is_empty() { return Err("No code found")?; } - let mut new_ast = VecDeque::from(ast); - loop { - if new_ast.is_empty() { - break; - } - let stmt = new_ast - .pop_front() - .unwrap_to_error("could not get statement")?; - get_functions(stmt, &mut functions, name); - } + get_functions_recurisve(ast, &mut functions, &mut Vec::new(), &mut Vec::new(), name)?; let mut starts = file_contents .match_indices('\n') .map(|x| x.0) @@ -118,7 +109,6 @@ pub(crate) fn find_function_in_file( let start = func.1 .0.row(); let end = func.1 .1.row(); let start = map[&(start - 1)]; - let end = map[&(end - 1)]; if let StmtKind::FunctionDef { name, @@ -161,56 +151,103 @@ pub(crate) fn find_function_in_file( Ok(new) } #[inline] -fn fun_name1( +fn get_functions_recurisve( body: Vec>, functions: &mut Vec<(StmtKind, (Location, Location))>, + current_parent: &mut Vec, + current_class: &mut Vec, lookup_name: &str, -) { +) -> Result<(), Box> { let mut new_ast = VecDeque::from(body); loop { if new_ast.is_empty() { break; } - let stmt = new_ast.pop_front().expect("could not get statement"); - get_functions(stmt, functions, lookup_name); + let stmt = new_ast.pop_front().unwrap_to_error("No stmt")?; + get_functions(stmt, functions, current_parent, current_class, lookup_name); } + Ok(()) } fn get_functions( stmt: Located, - functions: &mut Vec<(StmtKind, (Location, Location))>, + current_parent: &mut Vec, + current_class: &mut Vec, lookup_name: &str, ) { match stmt.node { - StmtKind::FunctionDef { ref name, .. } if name == lookup_name => if let Some(end) = stmt.end_location { - functions.push((stmt.node, (stmt.location, end))); - }, - + StmtKind::FunctionDef { ref name, .. } | StmtKind::AsyncFunctionDef { ref name, .. } + if name == lookup_name => + { + if let Some(end) = stmt.end_location { + functions.push((stmt.node, (stmt.location, end))); + } + } StmtKind::If { body, orelse, .. } | StmtKind::While { body, orelse, .. } - | StmtKind::For { body, orelse, .. } => { - fun_name1(body, functions, lookup_name); + | StmtKind::For { body, orelse, .. } + | StmtKind::AsyncFor { body, orelse, .. } => { + get_functions_recurisve(body, functions, current_parent, current_class, lookup_name) + .unwrap(); + get_functions_recurisve( + orelse, + functions, + current_parent, + current_class, + lookup_name, + ) + .unwrap(); + } + StmtKind::FunctionDef { + name: _, body: _, .. + } + | StmtKind::AsyncFunctionDef { + name: _, body: _, .. + } => { + // turn the function into a parent function + // and add it to the current parent + // and then recurse with the get_functions_recurisve + } + StmtKind::ClassDef { + name: _, body: _, .. + } => { + // turn the class into a python class - fun_name1(orelse, functions, lookup_name); + // and add it to the current class + // and then recurse with the get_functions_recurisve } - StmtKind::FunctionDef { body, .. } - | StmtKind::ClassDef { body, .. } - | StmtKind::With { body, .. } => { - fun_name1(body, functions, lookup_name); + StmtKind::With { body, .. } | StmtKind::AsyncWith { body, .. } => { + get_functions_recurisve(body, functions, current_parent, current_class, lookup_name) + .unwrap(); } + // TODO: add handles.body StmtKind::Try { body, orelse, finalbody, .. } => { - fun_name1(body, functions, lookup_name); - - fun_name1(orelse, functions, lookup_name); - - fun_name1(finalbody, functions, lookup_name); + get_functions_recurisve(body, functions, current_parent, current_class, lookup_name) + .unwrap(); + get_functions_recurisve( + orelse, + functions, + current_parent, + current_class, + lookup_name, + ) + .unwrap(); + get_functions_recurisve( + finalbody, + functions, + current_parent, + current_class, + lookup_name, + ) + .unwrap(); } + // TODO: add match.body _ => {} } } From b8b1d334893c2630886a3c377339acd3d44b899d Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 14 Nov 2022 13:21:13 -0500 Subject: [PATCH 126/172] working on parent functions and classes (python) --- cargo-function-history/Cargo.toml | 2 +- .../src/languages/python.rs | 122 ++++++++++++------ .../src/test_functions.py | 10 ++ 3 files changed, 91 insertions(+), 43 deletions(-) diff --git a/cargo-function-history/Cargo.toml b/cargo-function-history/Cargo.toml index 4f0cea34..fe13a360 100644 --- a/cargo-function-history/Cargo.toml +++ b/cargo-function-history/Cargo.toml @@ -27,4 +27,4 @@ dirs = "4.0.0" simple_file_logger = "0.2.0" log = "0.4" function_history_backend_thread = { path = "../function_history_backend_thread", version = "0.2.2", default-features = false} -tui-input = "0.6.0" \ No newline at end of file +tui-input = "0.6.1" \ No newline at end of file diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 02a3b0d3..0f51bb76 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -33,14 +33,14 @@ pub struct PythonFunction { pub(crate) parameters: Vec, pub(crate) parent: Vec, pub(crate) decorators: Vec, - pub(crate) class: Option, + pub(crate) class: Vec, pub(crate) lines: (usize, usize), pub(crate) returns: Option, } impl fmt::Display for PythonFunction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(ref class) = self.class { + for class in &self.class { write!(f, "{}", class.top)?; } for parent in &self.parent { @@ -50,9 +50,10 @@ impl fmt::Display for PythonFunction { for parent in &self.parent { write!(f, "{}", parent.bottom)?; } - self.class - .as_ref() - .map_or(Ok(()), |class| write!(f, "{}", class.bottom)) + for class in &self.class { + write!(f, "{}", class.bottom)?; + } + Ok(()) } } @@ -133,12 +134,12 @@ pub(crate) fn find_function_in_file( name: name.to_string(), returns: returns.as_ref().map(|x| x.node.name().to_string()), parameters: args.args.iter().map(|x| x.node.arg.to_string()).collect(), - parent: vec![], + parent: func.3, decorators: decorator_list .iter() .map(|x| x.node.name().to_string()) .collect(), - class: None, + class: func.2, body, lines: (*start, *end), }; @@ -153,7 +154,12 @@ pub(crate) fn find_function_in_file( #[inline] fn get_functions_recurisve( body: Vec>, - functions: &mut Vec<(StmtKind, (Location, Location))>, + functions: &mut Vec<( + StmtKind, + (Location, Location), + Vec, + Vec, + )>, current_parent: &mut Vec, current_class: &mut Vec, lookup_name: &str, @@ -171,7 +177,12 @@ fn get_functions_recurisve( fn get_functions( stmt: Located, - functions: &mut Vec<(StmtKind, (Location, Location))>, + functions: &mut Vec<( + StmtKind, + (Location, Location), + Vec, + Vec, + )>, current_parent: &mut Vec, current_class: &mut Vec, lookup_name: &str, @@ -181,7 +192,12 @@ fn get_functions( if name == lookup_name => { if let Some(end) = stmt.end_location { - functions.push((stmt.node, (stmt.location, end))); + functions.push(( + stmt.node, + (stmt.location, end), + current_class.clone(), + current_parent.clone(), + )); } } StmtKind::If { body, orelse, .. } @@ -199,23 +215,43 @@ fn get_functions( ) .unwrap(); } - StmtKind::FunctionDef { - name: _, body: _, .. - } - | StmtKind::AsyncFunctionDef { - name: _, body: _, .. - } => { + StmtKind::FunctionDef { name, body, .. } + | StmtKind::AsyncFunctionDef { name, body, .. } => { // turn the function into a parent function + let parent = PythonParentFunction { + name, + top: String::new(), + bottom: String::new(), + lines: (0, 0), + parameters: vec![], + decorators: vec![], + returns: None, + }; // and add it to the current parent + current_parent.push(parent); // and then recurse with the get_functions_recurisve + get_functions_recurisve(body, functions, current_parent, current_class, lookup_name) + .unwrap(); + // and then remove the parent function + current_parent.pop(); } - StmtKind::ClassDef { - name: _, body: _, .. - } => { + StmtKind::ClassDef { name, body, .. } => { // turn the class into a python class + let class = PythonClass { + name, + top: String::new(), + bottom: String::new(), + lines: (0, 0), + decorators: vec![], + }; // and add it to the current class + current_class.push(class); // and then recurse with the get_functions_recurisve + get_functions_recurisve(body, functions, current_parent, current_class, lookup_name) + .unwrap(); + // and then remove the class + current_class.pop(); } StmtKind::With { body, .. } | StmtKind::AsyncWith { body, .. } => { get_functions_recurisve(body, functions, current_parent, current_class, lookup_name) @@ -276,7 +312,7 @@ pub enum PythonFilter { impl PythonFilter { pub fn matches(&self, function: &PythonFunction) -> bool { match self { - Self::InClass(class) => function.class.as_ref().map_or(false, |x| x.name == *class), + Self::InClass(class) => function.class.iter().any(|c| c.name == *class), Self::HasParentFunction(parent) => function.parent.iter().any(|x| x.name == *parent), Self::HasReturnType(return_type) => function .returns @@ -288,8 +324,9 @@ impl PythonFilter { Self::HasDecorator(decorator) => function.decorators.iter().any(|x| x == decorator), Self::HasClasswithDecorator(decorator) => function .class - .as_ref() - .map_or(false, |x| x.decorators.iter().any(|x| x == decorator)), + .iter() + .any(|x| x.decorators.iter().any(|y| y == decorator)), + Self::HasParentFunctionwithDecorator(decorator) => function .parent .iter() @@ -309,9 +346,9 @@ impl PythonFilter { impl FunctionTrait for PythonFunction { fn get_tops(&self) -> Vec { let mut tops = Vec::new(); - self.class.as_ref().map_or((), |block| { - tops.push(block.top.clone()); - }); + for class in &self.class { + tops.push(class.top.clone()); + } for parent in &self.parent { tops.push(parent.top.clone()); } @@ -319,27 +356,28 @@ impl FunctionTrait for PythonFunction { } fn get_total_lines(&self) -> (usize, usize) { - self.class.as_ref().map_or_else( - || { - let mut start = self.lines.0; - let mut end = self.lines.1; - for parent in &self.parent { - if parent.lines.0 < start { - start = parent.lines.0; - end = parent.lines.1; - } - } - (start, end) - }, - |block| block.lines, - ) + let mut lines = (0, 0); + for class in &self.class { + if class.lines.0 < lines.0 { + lines = class.lines; + } + } + for parent in &self.parent { + if parent.lines.0 < lines.0 { + lines = parent.lines; + } + } + if self.lines.0 < lines.0 { + lines = self.lines; + } + lines } fn get_bottoms(&self) -> Vec { let mut bottoms = Vec::new(); - self.class.as_ref().map_or((), |block| { - bottoms.push(block.bottom.clone()); - }); + for class in &self.class { + bottoms.push(class.bottom.clone()); + } for parent in &self.parent { bottoms.push(parent.bottom.clone()); } diff --git a/git-function-history-lib/src/test_functions.py b/git-function-history-lib/src/test_functions.py index 679c1804..97df3dc0 100644 --- a/git-function-history-lib/src/test_functions.py +++ b/git-function-history-lib/src/test_functions.py @@ -16,3 +16,13 @@ def empty_test(t): def empty_test(n: int) -> list: """This is an empty test with a docstring""" pass + +class TestClass: + def test_method(self): + pass + + def test_with_assert(n): + @assert_that("This is a test with an assert") + def empty_test(t): + return t == n + assert True \ No newline at end of file From 1b976ecd0a683738d4fc147ca7b98c6d1a1f4128 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 14 Nov 2022 23:02:08 -0500 Subject: [PATCH 127/172] moving along code is kinda cleaner (mostly refactor) --- .../src/languages/python.rs | 330 ++++++++++++------ .../src/test_functions.py | 2 + 2 files changed, 219 insertions(+), 113 deletions(-) diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 0f51bb76..31499bc7 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -1,5 +1,5 @@ use rustpython_parser::{ - ast::{Located, Location, StmtKind}, + ast::{Arguments, ExprKind, Located, StmtKind}, parser, }; use std::collections::VecDeque; @@ -8,22 +8,6 @@ use std::{collections::HashMap, fmt}; use crate::{impl_function_trait, UnwrapToError}; use super::FunctionTrait; -// #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] -// pub struct Range { -// pub location: Location, -// pub end_location: Location, -// } - -// impl Range { -// pub fn from_located(located: &Located) -> Self { -// Range { -// location: located.location, -// end_location: located -// .end_location -// .expect("AST nodes should have end_location."), -// } -// } -// } #[derive(Debug, Clone)] pub struct PythonFunction { @@ -47,12 +31,6 @@ impl fmt::Display for PythonFunction { write!(f, "{}", parent.top)?; } write!(f, "{}", self.body)?; - for parent in &self.parent { - write!(f, "{}", parent.bottom)?; - } - for class in &self.class { - write!(f, "{}", class.bottom)?; - } Ok(()) } } @@ -68,7 +46,6 @@ impl fmt::Display for PythonFunction { pub struct PythonClass { pub(crate) name: String, pub(crate) top: String, - pub(crate) bottom: String, pub(crate) lines: (usize, usize), pub(crate) decorators: Vec, } @@ -76,7 +53,6 @@ pub struct PythonClass { pub struct PythonParentFunction { pub(crate) name: String, pub(crate) top: String, - pub(crate) bottom: String, pub(crate) lines: (usize, usize), pub(crate) parameters: Vec, pub(crate) decorators: Vec, @@ -90,11 +66,9 @@ pub(crate) fn find_function_in_file( ) -> Result, Box> { let ast = parser::parse_program(file_contents, "")?; let mut functions = vec![]; - if ast.is_empty() { return Err("No code found")?; } - get_functions_recurisve(ast, &mut functions, &mut Vec::new(), &mut Vec::new(), name)?; let mut starts = file_contents .match_indices('\n') .map(|x| x.0) @@ -105,22 +79,37 @@ pub(crate) fn find_function_in_file( .iter() .enumerate() .collect::>(); + get_functions_recurisve( + ast, + &map, + &mut functions, + &mut Vec::new(), + &mut Vec::new(), + name, + )?; let mut new = Vec::new(); for func in functions { - let start = func.1 .0.row(); - let end = func.1 .1.row(); - let start = map[&(start - 1)]; - let end = map[&(end - 1)]; + let start = func.0.location.row(); + let end = func.0.end_location.unwrap().row(); + let starts = map[&(start - 1)]; + let ends = map[&(end - 1)]; if let StmtKind::FunctionDef { name, args, decorator_list, returns, .. - } = func.0 + } + | StmtKind::AsyncFunctionDef { + name, + args, + decorator_list, + returns, + .. + } = func.0.node { - let mut start_s = func.1 .0.row(); - let body = file_contents[*start..*end] + let mut start_s = func.0.location.row(); + let body = file_contents[*starts..*ends] .trim_start_matches('\n') .to_string() .lines() @@ -130,18 +119,83 @@ pub(crate) fn find_function_in_file( t }) .collect::(); + let class = func + .1 + .iter() + .filter_map(|class| { + if let StmtKind::ClassDef { + ref name, + ref decorator_list, + .. + } = class.node + { + let start = class.location.row(); + if let Some(end) = class.end_location { + let end = end.row(); + let top = file_contents.lines().nth(start - 1).unwrap(); + let top = format!("{start}: {top}\n"); + let decorators = get_decorator_list(decorator_list.clone()); + return Some(PythonClass { + name: name.to_string(), + top, + lines: (start, end), + decorators, + }); + } + } + None + }) + .collect::>(); + let parent = func + .2 + .iter() + .filter_map(|parent| { + if let StmtKind::FunctionDef { + ref name, + ref args, + ref decorator_list, + ref returns, + .. + } + | StmtKind::AsyncFunctionDef { + ref name, + ref args, + ref decorator_list, + ref returns, + .. + } = parent.node + { + let start = parent.location.row(); + if let Some(end) = parent.end_location { + let end = end.row(); + let top = file_contents.lines().nth(start - 1).unwrap(); + let top = format!("{start}: {top}\n"); + let decorators = get_decorator_list(decorator_list.clone()); + let parameters = get_args(*args.clone()); + let returns = get_return_type(returns.clone()); + return Some(PythonParentFunction { + name: name.to_string(), + top, + lines: (start, end), + parameters, + decorators, + returns, + }); + } + } + None + }) + .collect::>(); + let new_func = PythonFunction { name: name.to_string(), - returns: returns.as_ref().map(|x| x.node.name().to_string()), - parameters: args.args.iter().map(|x| x.node.arg.to_string()).collect(), - parent: func.3, - decorators: decorator_list - .iter() - .map(|x| x.node.name().to_string()) - .collect(), - class: func.2, + parameters: get_args(*args), + parent, + decorators: get_decorator_list(decorator_list), + returns: get_return_type(returns), + class, body, - lines: (*start, *end), + lines: (start, end), }; new.push(new_func); } @@ -154,14 +208,14 @@ pub(crate) fn find_function_in_file( #[inline] fn get_functions_recurisve( body: Vec>, + map: &HashMap, functions: &mut Vec<( - StmtKind, - (Location, Location), - Vec, - Vec, + Located, + Vec>, + Vec>, )>, - current_parent: &mut Vec, - current_class: &mut Vec, + current_parent: &mut Vec>, + current_class: &mut Vec>, lookup_name: &str, ) -> Result<(), Box> { let mut new_ast = VecDeque::from(body); @@ -170,44 +224,55 @@ fn get_functions_recurisve( break; } let stmt = new_ast.pop_front().unwrap_to_error("No stmt")?; - get_functions(stmt, functions, current_parent, current_class, lookup_name); + get_functions( + stmt, + map, + functions, + current_parent, + current_class, + lookup_name, + ); } Ok(()) } fn get_functions( stmt: Located, + map: &HashMap, functions: &mut Vec<( - StmtKind, - (Location, Location), - Vec, - Vec, + Located, + Vec>, + Vec>, )>, - current_parent: &mut Vec, - current_class: &mut Vec, + current_parent: &mut Vec>, + current_class: &mut Vec>, lookup_name: &str, ) { + let stmt_clone = stmt.clone(); match stmt.node { StmtKind::FunctionDef { ref name, .. } | StmtKind::AsyncFunctionDef { ref name, .. } if name == lookup_name => { - if let Some(end) = stmt.end_location { - functions.push(( - stmt.node, - (stmt.location, end), - current_class.clone(), - current_parent.clone(), - )); + if stmt.end_location.is_some() { + functions.push((stmt, current_class.clone(), current_parent.clone())); } } StmtKind::If { body, orelse, .. } | StmtKind::While { body, orelse, .. } | StmtKind::For { body, orelse, .. } | StmtKind::AsyncFor { body, orelse, .. } => { - get_functions_recurisve(body, functions, current_parent, current_class, lookup_name) - .unwrap(); + get_functions_recurisve( + body, + map, + functions, + current_parent, + current_class, + lookup_name, + ) + .unwrap(); get_functions_recurisve( orelse, + map, functions, current_parent, current_class, @@ -215,59 +280,61 @@ fn get_functions( ) .unwrap(); } - StmtKind::FunctionDef { name, body, .. } - | StmtKind::AsyncFunctionDef { name, body, .. } => { - // turn the function into a parent function - let parent = PythonParentFunction { - name, - top: String::new(), - bottom: String::new(), - lines: (0, 0), - parameters: vec![], - decorators: vec![], - returns: None, - }; - // and add it to the current parent - current_parent.push(parent); - // and then recurse with the get_functions_recurisve - get_functions_recurisve(body, functions, current_parent, current_class, lookup_name) - .unwrap(); - // and then remove the parent function + StmtKind::FunctionDef { body, .. } | StmtKind::AsyncFunctionDef { body, .. } => { + current_parent.push(stmt_clone); + get_functions_recurisve( + body, + map, + functions, + current_parent, + current_class, + lookup_name, + ) + .unwrap(); current_parent.pop(); } - StmtKind::ClassDef { name, body, .. } => { - // turn the class into a python class - let class = PythonClass { - name, - top: String::new(), - bottom: String::new(), - lines: (0, 0), - decorators: vec![], - }; - - // and add it to the current class - current_class.push(class); - // and then recurse with the get_functions_recurisve - get_functions_recurisve(body, functions, current_parent, current_class, lookup_name) - .unwrap(); - // and then remove the class + StmtKind::ClassDef { body, .. } => { + current_class.push(stmt_clone); + get_functions_recurisve( + body, + map, + functions, + current_parent, + current_class, + lookup_name, + ) + .unwrap(); current_class.pop(); } StmtKind::With { body, .. } | StmtKind::AsyncWith { body, .. } => { - get_functions_recurisve(body, functions, current_parent, current_class, lookup_name) - .unwrap(); + get_functions_recurisve( + body, + map, + functions, + current_parent, + current_class, + lookup_name, + ) + .unwrap(); } - // TODO: add handles.body StmtKind::Try { body, orelse, finalbody, .. } => { - get_functions_recurisve(body, functions, current_parent, current_class, lookup_name) - .unwrap(); + get_functions_recurisve( + body, + map, + functions, + current_parent, + current_class, + lookup_name, + ) + .unwrap(); get_functions_recurisve( orelse, + map, functions, current_parent, current_class, @@ -276,6 +343,7 @@ fn get_functions( .unwrap(); get_functions_recurisve( finalbody, + map, functions, current_parent, current_class, @@ -283,10 +351,52 @@ fn get_functions( ) .unwrap(); } - // TODO: add match.body _ => {} } } + +fn get_args(args: Arguments) -> Vec { + let mut new_args = Vec::new(); + for arg in args.args { + new_args.push(arg.node.arg.to_string()); + } + for arg in args.kwonlyargs { + new_args.push(arg.node.arg.to_string()); + } + for arg in args.kw_defaults { + new_args.push(arg.node.name().to_string()); + } + for arg in args.defaults { + new_args.push(arg.node.name().to_string()); + } + if let Some(arg) = args.vararg { + new_args.push(arg.node.arg.to_string()); + } + if let Some(arg) = args.kwarg { + new_args.push(arg.node.arg.to_string()); + } + for arg in args.posonlyargs { + new_args.push(arg.node.arg.to_string()); + } + new_args +} + +fn get_return_type(retr: Option>>) -> Option { + if let Some(retr) = retr { + if let ExprKind::Name { ref id, .. } = retr.node { + return Some(id.to_string()); + } + } + None +} + +fn get_decorator_list(decorator_list: Vec>) -> Vec { + decorator_list + .iter() + .map(|x| x.node.name().to_string()) + .collect::>() +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum PythonFilter { /// when you want to filter by function that are in a specific class @@ -374,14 +484,8 @@ impl FunctionTrait for PythonFunction { } fn get_bottoms(&self) -> Vec { - let mut bottoms = Vec::new(); - for class in &self.class { - bottoms.push(class.bottom.clone()); - } - for parent in &self.parent { - bottoms.push(parent.bottom.clone()); - } - bottoms + // in python there is no bottom + Vec::new() } impl_function_trait!(PythonFunction); } diff --git a/git-function-history-lib/src/test_functions.py b/git-function-history-lib/src/test_functions.py index 97df3dc0..63b1b396 100644 --- a/git-function-history-lib/src/test_functions.py +++ b/git-function-history-lib/src/test_functions.py @@ -9,6 +9,8 @@ def test_with_assert(n): @assert_that("This is a test with an assert") def empty_test(t): return t == n + + assert True passing_test = test_with_assert From 0d33a9721ed869da00845377ffefec7f232893d6 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Tue, 15 Nov 2022 16:15:33 -0500 Subject: [PATCH 128/172] removed most panicking code from python.rs --- .../src/languages/python.rs | 63 +++++++++---------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 31499bc7..f8eef9fb 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -86,11 +86,15 @@ pub(crate) fn find_function_in_file( &mut Vec::new(), &mut Vec::new(), name, - )?; + ); let mut new = Vec::new(); for func in functions { let start = func.0.location.row(); - let end = func.0.end_location.unwrap().row(); + let end = func + .0 + .end_location + .unwrap_to_error("no end location for this function")? + .row(); let starts = map[&(start - 1)]; let ends = map[&(end - 1)]; if let StmtKind::FunctionDef { @@ -132,7 +136,10 @@ pub(crate) fn find_function_in_file( let start = class.location.row(); if let Some(end) = class.end_location { let end = end.row(); - let top = file_contents.lines().nth(start - 1).unwrap(); + let top = match file_contents.lines().nth(start - 1) { + Some(l) => l.to_string(), + None => return None, + }; let top = format!("{start}: {top}\n"); let decorators = get_decorator_list(decorator_list.clone()); return Some(PythonClass { @@ -168,7 +175,10 @@ pub(crate) fn find_function_in_file( let start = parent.location.row(); if let Some(end) = parent.end_location { let end = end.row(); - let top = file_contents.lines().nth(start - 1).unwrap(); + let top = match file_contents.lines().nth(start - 1) { + Some(l) => l.to_string(), + None => return None, + }; let top = format!("{start}: {top}\n"); let decorators = get_decorator_list(decorator_list.clone()); let parameters = get_args(*args.clone()); @@ -217,13 +227,13 @@ fn get_functions_recurisve( current_parent: &mut Vec>, current_class: &mut Vec>, lookup_name: &str, -) -> Result<(), Box> { +) { let mut new_ast = VecDeque::from(body); loop { if new_ast.is_empty() { break; } - let stmt = new_ast.pop_front().unwrap_to_error("No stmt")?; + let stmt = new_ast.pop_front().expect("No stmt found edge case shouldn't happen please file a bug to https://github.com/mendelsshop/git_function_history/issues"); get_functions( stmt, map, @@ -233,7 +243,6 @@ fn get_functions_recurisve( lookup_name, ); } - Ok(()) } fn get_functions( @@ -268,8 +277,7 @@ fn get_functions( current_parent, current_class, lookup_name, - ) - .unwrap(); + ); get_functions_recurisve( orelse, map, @@ -277,8 +285,7 @@ fn get_functions( current_parent, current_class, lookup_name, - ) - .unwrap(); + ); } StmtKind::FunctionDef { body, .. } | StmtKind::AsyncFunctionDef { body, .. } => { current_parent.push(stmt_clone); @@ -289,8 +296,7 @@ fn get_functions( current_parent, current_class, lookup_name, - ) - .unwrap(); + ); current_parent.pop(); } StmtKind::ClassDef { body, .. } => { @@ -302,21 +308,17 @@ fn get_functions( current_parent, current_class, lookup_name, - ) - .unwrap(); + ); current_class.pop(); } - StmtKind::With { body, .. } | StmtKind::AsyncWith { body, .. } => { - get_functions_recurisve( - body, - map, - functions, - current_parent, - current_class, - lookup_name, - ) - .unwrap(); - } + StmtKind::With { body, .. } | StmtKind::AsyncWith { body, .. } => get_functions_recurisve( + body, + map, + functions, + current_parent, + current_class, + lookup_name, + ), StmtKind::Try { body, orelse, @@ -330,8 +332,7 @@ fn get_functions( current_parent, current_class, lookup_name, - ) - .unwrap(); + ); get_functions_recurisve( orelse, map, @@ -339,8 +340,7 @@ fn get_functions( current_parent, current_class, lookup_name, - ) - .unwrap(); + ); get_functions_recurisve( finalbody, map, @@ -348,8 +348,7 @@ fn get_functions( current_parent, current_class, lookup_name, - ) - .unwrap(); + ); } _ => {} } From e56eeda646aaf1f2781cc85eaff2f93fc9332aed Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Tue, 15 Nov 2022 19:27:07 -0500 Subject: [PATCH 129/172] made python args have more info such as type of arg and type --- .../src/languages/python.rs | 119 +++++++++++++----- .../src/test_functions.py | 10 +- 2 files changed, 97 insertions(+), 32 deletions(-) diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index f8eef9fb..7d51793d 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -13,8 +13,7 @@ use super::FunctionTrait; pub struct PythonFunction { pub(crate) name: String, pub(crate) body: String, - /// parameters: Params, - pub(crate) parameters: Vec, + pub(crate) parameters: Params, pub(crate) parent: Vec, pub(crate) decorators: Vec, pub(crate) class: Vec, @@ -35,13 +34,34 @@ impl fmt::Display for PythonFunction { } } -/// #[derive(Debug, Clone)] -/// pub struct Params { -/// args: Vec, -/// kwargs: Vec, -/// varargs: Option, -/// varkwargs: Option, -/// } +#[derive(Debug, Clone)] +pub struct Param { + pub name: String, + pub r#type: Option, +} + +#[derive(Debug, Clone)] +pub struct Params { + pub args: Vec, + pub kwargs: Vec, + pub posonlyargs: Vec, + pub varargs: Option, + pub varkwargs: Option, +} + +impl Params { + pub fn arg_has_name(&self, name: &str) -> bool { + self.args.iter().any(|arg| arg.name == name) + || self.kwargs.iter().any(|arg| arg.name == name) + || self.posonlyargs.iter().any(|arg| arg.name == name) + || self.varargs.as_ref().map_or(false, |arg| arg.name == name) + || self + .varkwargs + .as_ref() + .map_or(false, |arg| arg.name == name) + } +} + #[derive(Debug, Clone)] pub struct PythonClass { pub(crate) name: String, @@ -54,9 +74,8 @@ pub struct PythonParentFunction { pub(crate) name: String, pub(crate) top: String, pub(crate) lines: (usize, usize), - pub(crate) parameters: Vec, + pub(crate) parameters: Params, pub(crate) decorators: Vec, - /// pub(crate) class: Option, pub(crate) returns: Option, } @@ -354,30 +373,75 @@ fn get_functions( } } -fn get_args(args: Arguments) -> Vec { - let mut new_args = Vec::new(); +fn get_args(args: Arguments) -> Params { + let mut parameters = Params { + args: Vec::new(), + varargs: None, + posonlyargs: Vec::new(), + kwargs: Vec::new(), + varkwargs: None, + }; for arg in args.args { - new_args.push(arg.node.arg.to_string()); + parameters.args.push(Param { + name: arg.node.arg, + r#type: arg.node.annotation.and_then(|x| { + if let ExprKind::Name { id, .. } = x.node { + Some(id) + } else { + None + } + }), + }); } for arg in args.kwonlyargs { - new_args.push(arg.node.arg.to_string()); - } - for arg in args.kw_defaults { - new_args.push(arg.node.name().to_string()); - } - for arg in args.defaults { - new_args.push(arg.node.name().to_string()); + parameters.kwargs.push(Param { + name: arg.node.arg, + r#type: arg.node.annotation.and_then(|x| { + if let ExprKind::Name { id, .. } = x.node { + Some(id) + } else { + None + } + }), + }); } if let Some(arg) = args.vararg { - new_args.push(arg.node.arg.to_string()); + parameters.varargs = Some(Param { + name: arg.node.arg, + r#type: arg.node.annotation.and_then(|x| { + if let ExprKind::Name { id, .. } = x.node { + Some(id) + } else { + None + } + }), + }); } if let Some(arg) = args.kwarg { - new_args.push(arg.node.arg.to_string()); + parameters.varkwargs = Some(Param { + name: arg.node.arg, + r#type: arg.node.annotation.and_then(|x| { + if let ExprKind::Name { id, .. } = x.node { + Some(id) + } else { + None + } + }), + }); } for arg in args.posonlyargs { - new_args.push(arg.node.arg.to_string()); + parameters.posonlyargs.push(Param { + name: arg.node.arg, + r#type: arg.node.annotation.and_then(|x| { + if let ExprKind::Name { id, .. } = x.node { + Some(id) + } else { + None + } + }), + }); } - new_args + parameters } fn get_return_type(retr: Option>>) -> Option { @@ -428,14 +492,13 @@ impl PythonFilter { .as_ref() .map_or(false, |x| x == return_type), Self::HasParameterName(parameter_name) => { - function.parameters.iter().any(|x| x == parameter_name) + function.parameters.arg_has_name(parameter_name) } Self::HasDecorator(decorator) => function.decorators.iter().any(|x| x == decorator), Self::HasClasswithDecorator(decorator) => function .class .iter() .any(|x| x.decorators.iter().any(|y| y == decorator)), - Self::HasParentFunctionwithDecorator(decorator) => function .parent .iter() @@ -443,7 +506,7 @@ impl PythonFilter { Self::HasParentFunctionwithParameterName(parameter_name) => function .parent .iter() - .any(|x| x.parameters.iter().any(|x| x == parameter_name)), + .any(|x| x.parameters.arg_has_name(parameter_name)), Self::HasParentFunctionwithReturnType(return_type) => function .parent .iter() diff --git a/git-function-history-lib/src/test_functions.py b/git-function-history-lib/src/test_functions.py index 63b1b396..a9ce9f17 100644 --- a/git-function-history-lib/src/test_functions.py +++ b/git-function-history-lib/src/test_functions.py @@ -5,14 +5,15 @@ # def empty_test(): # print("This is an empty test") -def test_with_assert(n): +def test_with_assert(y, n,/,c=7, *, a , args, **kwargs): @assert_that("This is a test with an assert") def empty_test(t): return t == n assert True - +class Test: + pass passing_test = test_with_assert @def_test def empty_test(n: int) -> list: @@ -23,8 +24,9 @@ class TestClass: def test_method(self): pass - def test_with_assert(n): + def test_with_assert(n: Test): @assert_that("This is a test with an assert") def empty_test(t): return t == n - assert True \ No newline at end of file + assert True + From c8534562de227728f04bab2493346b1e24b8de07 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 16 Nov 2022 01:14:06 -0500 Subject: [PATCH 130/172] wip fixinf formating --- git-function-history-lib/src/languages/go.rs | 12 ++-- git-function-history-lib/src/languages/mod.rs | 12 +++- .../src/languages/python.rs | 52 ++++++-------- .../src/languages/ruby.rs | 68 +++++++++++-------- .../src/languages/rust.rs | 40 ++++------- git-function-history-lib/src/lib.rs | 35 +++++++--- 6 files changed, 114 insertions(+), 105 deletions(-) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index bab6190a..da97dd9a 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -91,14 +91,14 @@ pub(crate) fn find_function_in_file( if let Some(recv) = func.recv { lines.0 = recv.pos(); } + // TODO: make sure that func is not commented out lines.0 = file_contents[..lines.0].rfind("func")?; - for i in &func.docs { if i.pos < lines.0 { lines.0 = i.pos; } } - let body = file_contents[lines.0..=lines.1].to_string(); + let mut body = file_contents[lines.0..=lines.1].to_string().trim_end().to_string(); let mut start_line = 0; for i in file_contents.chars().enumerate() { if i.1 == '\n' { @@ -119,10 +119,10 @@ pub(crate) fn find_function_in_file( end_line += 1; } } - - lines.0 = start_line; - lines.1 = end_line; - + lines.0 = start_line + 1; + lines.1 = end_line + 1; + let start = start_line + 1; + body = super::make_lined(body, start); // see if the first parameter has a name: let mut parameters = func.typ.params.list.get(0).map_or_else( || GoParameter::Type(vec![]), diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 539a6fb8..48fe2bd7 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -137,7 +137,7 @@ macro_rules! impl_function_trait { self.name.clone() } fn get_body(&self) -> String { - self.body.clone() + self.body.to_string() } }; } @@ -156,9 +156,9 @@ pub fn fmt_with_context( write!(f, "{}", current.get_body())?; } else if prev.get_total_lines() == current.get_total_lines() { write!(f, "{}", current.get_body())?; - write!(f, "{}", current.get_bottoms().join("\n"))?; + write!(f, "{}", current.get_bottoms().join("\n...\n"))?; } else if next.get_total_lines() == current.get_total_lines() { - write!(f, "{}", current.get_tops().join("\n"))?; + write!(f, "{}", current.get_tops().join("\n...\n"))?; write!(f, "{}", current.get_body())?; } else { write!(f, "{current}")?; @@ -186,6 +186,12 @@ pub fn fmt_with_context( Ok(()) } +fn make_lined(snippet: String, mut start: usize) -> String { + snippet.lines().map(|line| {let new = format!("{}: {}\n", start, line); + start += 1; + new +}).collect::().trim_end().to_string()} + pub trait FileTrait: fmt::Debug + fmt::Display { fn get_file_name(&self) -> String; fn get_functions(&self) -> Vec>; diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 7d51793d..4386d7b0 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -24,13 +24,12 @@ pub struct PythonFunction { impl fmt::Display for PythonFunction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for class in &self.class { - write!(f, "{}", class.top)?; + write!(f, "{}\n...\n", class.top)?; } for parent in &self.parent { - write!(f, "{}", parent.top)?; + write!(f, "{}\n...\n", parent.top)?; } - write!(f, "{}", self.body)?; - Ok(()) + write!(f, "{}", self.body) } } @@ -131,17 +130,11 @@ pub(crate) fn find_function_in_file( .. } = func.0.node { - let mut start_s = func.0.location.row(); - let body = file_contents[*starts..*ends] + let start_s = func.0.location.row(); + let mut body = file_contents[*starts..*ends] .trim_start_matches('\n') - .to_string() - .lines() - .map(|l| { - let t = format!("{start_s}: {l}\n",); - start_s += 1; - t - }) - .collect::(); + .to_string(); + body = super::make_lined(body, start_s); let class = func .1 .iter() @@ -156,10 +149,10 @@ pub(crate) fn find_function_in_file( if let Some(end) = class.end_location { let end = end.row(); let top = match file_contents.lines().nth(start - 1) { - Some(l) => l.to_string(), + Some(l) => l.trim_end().to_string(), None => return None, }; - let top = format!("{start}: {top}\n"); + let top = format!("{start}: {top}"); let decorators = get_decorator_list(decorator_list.clone()); return Some(PythonClass { name: name.to_string(), @@ -195,10 +188,10 @@ pub(crate) fn find_function_in_file( if let Some(end) = parent.end_location { let end = end.row(); let top = match file_contents.lines().nth(start - 1) { - Some(l) => l.to_string(), + Some(l) => l.trim_end().to_string(), None => return None, }; - let top = format!("{start}: {top}\n"); + let top = format!("{start}: {top}"); let decorators = get_decorator_list(decorator_list.clone()); let parameters = get_args(*args.clone()); let returns = get_return_type(returns.clone()); @@ -528,21 +521,14 @@ impl FunctionTrait for PythonFunction { } fn get_total_lines(&self) -> (usize, usize) { - let mut lines = (0, 0); - for class in &self.class { - if class.lines.0 < lines.0 { - lines = class.lines; - } - } - for parent in &self.parent { - if parent.lines.0 < lines.0 { - lines = parent.lines; - } - } - if self.lines.0 < lines.0 { - lines = self.lines; - } - lines + // find the first line of the function (could be the parent or the class) + self + .class + .iter() + .map(|x| x.lines) + .chain(self.parent.iter().map(|x| x.lines)) + .min() + .unwrap_or(self.lines) } fn get_bottoms(&self) -> Vec { diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 63b621cb..b63132e4 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -39,12 +39,12 @@ impl RubyFunction { impl fmt::Display for RubyFunction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.class { - Some(class) => write!(f, "{}", class.top)?, + Some(class) => write!(f, "{}\n...\n", class.top)?, None => {} } write!(f, "{}", self.body)?; match &self.class { - Some(class) => write!(f, "{}", class.bottom)?, + Some(class) => write!(f, "\n...\n{}", class.bottom)?, None => {} } Ok(()) @@ -104,25 +104,27 @@ pub(crate) fn find_function_in_file( .source(&parsed.input) .unwrap_to_error("Failed to get source")?; top = top.trim_end().to_string(); - top.push('\n'); - let mut starts = start_line; + top = super::make_lined(top, start_line+1); Some(RubyClass { name: parser_class_name(c), line: (start_line, end_line), superclass: parse_superclass(c), - top: top - .lines() - .map(|l| { - starts += 1; - format!("{starts}: {l}\n",) - }) - .collect(), - bottom: format!( - "{end_line}: {}", + top: top, + bottom: + // format!( + // "{end_line}: {}", + // loc_end + // .source(&parsed.input) + // .expect("Failed to get source") + // .trim_matches('\n') + // ), + super::make_lined( loc_end .source(&parsed.input) - .expect("Failed to get source") + .unwrap_to_error("Failed to get source")? .trim_matches('\n') + .to_string(), + end_line + 1, ), }) } @@ -149,23 +151,33 @@ pub(crate) fn find_function_in_file( end_line += 1; } } - let mut starts = start_line; + let starts = start_line + 1; Ok(RubyFunction { name: f.name.clone(), - lines: (start_line, end_line), + lines: (start_line + 1, end_line + 1), class, - body: f - .expression_l - .with_begin(start) - .source(&parsed.input) - .expect("Failed to get function body") - .trim_matches('\n') - .lines() - .map(|l| { - starts += 1; - format!("{starts}: {l}\n",) - }) - .collect(), + body: + // f + // .expression_l + // .with_begin(start) + // .source(&parsed.input) + // .expect("Failed to get function body") + // .trim_matches('\n') + // .lines() + // .map(|l| { + // starts += 1; + // format!("{starts}: {l}\n",) + // }) + // .collect::().trim_end().to_string(), + super::make_lined( + f.expression_l + .with_begin(start) + .source(&parsed.input) + .expect("Failed to get function body") + .trim_matches('\n') + .to_string(), + starts, + ), args: f .args .clone() diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 8c1e0fe4..48242ba9 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -62,7 +62,7 @@ impl fmt::Display for RustFunction { } match &self.block { None => {} - Some(block) => write!(f, "\n...{}", block.bottom)?, + Some(block) => write!(f, "\n...\n{}", block.bottom)?, }; Ok(()) } @@ -306,20 +306,14 @@ pub(crate) fn find_function_in_file( parent = p.parent(); } let attr = get_doc_comments_and_attrs(f); - let mut start = stuff.0 .0; + let start = stuff.0 .0; let bb = match map[&start] { 0 => 0, x => x + 1, }; let contents: String = file_contents[bb..f.syntax().text_range().end().into()] - .to_string() - .lines() - .map(|l| { - start += 1; - format!("{start}: {l}\n",) - }) - .collect(); - let body = contents.trim_end().to_string(); + .to_string(); + let body = super::make_lined(contents, start + 1); let function = RustFunction { name: f .name() @@ -399,7 +393,7 @@ fn get_stuff( found_start_brace = usize::from(start); } let start = map[&start_line]; - let mut start_lines = start_line; + let start_lines = start_line; let mut content: String = file[(*start)..=found_start_brace].to_string(); if &content[..1] == "\n" { content = content[1..].to_string(); @@ -407,25 +401,16 @@ fn get_stuff( ( (start_line, end_line), ( - content - .lines() - .map(|l| { - start_lines += 1; - format!("{start_lines}: {l}\n",) - }) - .collect::() - .trim_end() - .to_string(), - format!( - "\n{}: {}", - end_line, + super::make_lined(content, start_lines + 1), + super::make_lined( file.lines() .nth(if end_line == file.lines().count() - 1 { end_line } else { end_line - 1 }) - .unwrap_or("") + .unwrap_or("").to_string(), + end_line, ), ), (starts, end_line), @@ -619,12 +604,13 @@ impl FunctionTrait for RustFunction { fn get_bottoms(&self) -> Vec { let mut bottoms = Vec::new(); - self.block.as_ref().map_or((), |block| { - bottoms.push(block.bottom.clone()); - }); + for parent in &self.function { bottoms.push(parent.bottom.clone()); } + self.block.as_ref().map_or((), |block| { + bottoms.push(block.bottom.clone()); + }); bottoms } diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 2eb39480..711bb405 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -732,15 +732,12 @@ mod tests { } #[test] - fn python() { + fn python_whole() { let now = Utc::now(); let output = get_function_history( "empty_test", &FileFilterType::Relative("src/test_functions.py".to_string()), - &Filter::DateRange( - "03 Oct 2022 11:27:23 -0400".to_owned(), - "04 Oct 2022 23:45:52 +0000".to_owned(), - ), + &Filter::None, &languages::Language::Python, ); let after = Utc::now() - now; @@ -758,6 +755,30 @@ mod tests { let _functions = file.get_functions(); } + #[test] + fn ruby_whole() { + let now = Utc::now(); + let output = get_function_history( + "empty_test", + &FileFilterType::Relative("src/test_functions.rb".to_string()), + &Filter::None, + &languages::Language::Ruby, + ); + let after = Utc::now() - now; + println!("time taken: {}", after.num_seconds()); + match &output { + Ok(functions) => { + println!("{functions}"); + } + Err(e) => println!("{e}"), + } + assert!(output.is_ok()); + let output = output.unwrap(); + let commit = output.get_commit(); + let file = commit.get_file(); + let _functions = file.get_functions(); + } + // #[test] // #[cfg(feature = "c_lang")] // fn c_lang() { @@ -781,10 +802,8 @@ mod tests { // } #[test] #[cfg(feature = "unstable")] - fn go() { + fn go_whole() { let now = Utc::now(); - // sleep(Duration::from_secs(2)); - println!("go STARTING"); let output = get_function_history( "empty_test", &FileFilterType::Relative("src/test_functions.go".to_string()), From 7a5f91881181d191713127764b15b7445713a138 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Wed, 16 Nov 2022 13:54:11 -0500 Subject: [PATCH 131/172] fixed ruby formating (i think) --- .../src/languages/ruby.rs | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index b63132e4..2690b589 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -82,23 +82,19 @@ pub(crate) fn find_function_in_file( } } let mut end_line = 0; - let mut end_char = 0; for i in file_contents.chars().enumerate() { if i.1 == '\n' { if i.0 > c.expression_l.end { break; } - end_char = i.0; end_line += 1; } } - let loc_end = Loc { - begin: end_char, - end: c.expression_l.end, - }; + let loc_end = c.end_l; let top = Loc { begin: c.expression_l.begin, - end: c.body.as_ref().map_or(0, |b| b.expression().begin), + // TODO: check if there is a super class map_or to that + end: c.body.as_ref().map_or(c.keyword_l.end, |b| b.expression().begin), }; let mut top = top .source(&parsed.input) @@ -110,21 +106,13 @@ pub(crate) fn find_function_in_file( line: (start_line, end_line), superclass: parse_superclass(c), top: top, - bottom: - // format!( - // "{end_line}: {}", - // loc_end - // .source(&parsed.input) - // .expect("Failed to get source") - // .trim_matches('\n') - // ), - super::make_lined( + bottom: super::make_lined( loc_end .source(&parsed.input) .unwrap_to_error("Failed to get source")? .trim_matches('\n') .to_string(), - end_line + 1, + end_line, ), }) } From 9217dd1fbb9b8f3540eca543d8d6087a1372ca9c Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 17 Nov 2022 00:14:33 -0500 Subject: [PATCH 132/172] stiill atempting to fix rust formating, and getting the bottoms of classes parent functions etc --- git-function-history-lib/src/languages/mod.rs | 61 +++++++++++++++++-- .../src/languages/rust.rs | 24 ++++---- 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 48fe2bd7..27e8c9f2 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -1,7 +1,7 @@ use crate::Filter; use std::{ error::Error, - fmt::{self, Display}, + fmt::{self, Display}, collections::HashMap, }; // TODO: lisp/scheme js, java?(https://github.com/tanin47/javaparser.rs) php?(https://docs.rs/tagua-parser/0.1.0/tagua_parser/) use self::{python::PythonFunction, ruby::RubyFunction, rust::RustFunction}; @@ -141,7 +141,7 @@ macro_rules! impl_function_trait { } }; } - +// TODO: rewrite/fix this pub fn fmt_with_context( current: &T, prev: Option<&T>, @@ -150,21 +150,23 @@ pub fn fmt_with_context( ) -> fmt::Result { match (prev, next) { (Some(prev), Some(next)) => { + // println!("prev: {:?}, current {:?}. next: {:?}", prev.get_total_lines(), current.get_total_lines(), next.get_total_lines()); if prev.get_total_lines() == current.get_total_lines() && next.get_total_lines() == current.get_total_lines() { write!(f, "{}", current.get_body())?; } else if prev.get_total_lines() == current.get_total_lines() { write!(f, "{}", current.get_body())?; - write!(f, "{}", current.get_bottoms().join("\n...\n"))?; + write!(f, "{}", current.get_bottoms().into_iter().map(|x|format!("\n...\n{x}")).collect::())?; } else if next.get_total_lines() == current.get_total_lines() { - write!(f, "{}", current.get_tops().join("\n...\n"))?; + write!(f, "{}", current.get_tops().into_iter().map(|x|format!("{x}\n...\n")).collect::())?; write!(f, "{}", current.get_body())?; } else { write!(f, "{current}")?; } } (Some(prev), None) => { + // println!("prev: {:?}, current {:?}", prev.get_total_lines(), current.get_total_lines()); if prev.get_total_lines() == current.get_total_lines() { write!(f, "{}", current.get_body())?; } else { @@ -172,6 +174,7 @@ pub fn fmt_with_context( } } (None, Some(next)) => { + // println!("current {:?}. next: {:?}", current.get_total_lines(), next.get_total_lines()); if next.get_total_lines() == current.get_total_lines() { write!(f, "{}", current.get_body())?; } else { @@ -179,6 +182,7 @@ pub fn fmt_with_context( } } (None, None) => { + // println!("current {:?}", current.get_total_lines()); // print the function write!(f, "{current}")?; } @@ -201,6 +205,51 @@ pub trait FileTrait: fmt::Debug + fmt::Display { fn get_current(&self) -> Option>; } +fn turn_into_index(snippet: &str) -> HashMap> { + // turn snippet into a hashmap of line number to char index + // so line 1 is 0 to 10, line 2 is 11 to 20, etc + let mut index = HashMap::new(); + index.insert(1, vec![0]); + let mut line: usize = 1; + let mut char_index: usize = 0; + for c in snippet.chars() { + println!("{}: {}", line, char_index); + println!("index: {:?}", index); + if c == '\n' { + line += 1; + index.insert(line, vec![char_index + 1]); + } else { + index.get_mut(&line).unwrap().push(char_index); + } + char_index += c.len_utf8(); + + } + + index +} + +fn get_from_index(index: &HashMap>, char: usize) -> usize { + // gets the line number from the index + *index.iter().find(|(_, v)| v.contains(&char)).unwrap().0 +} + +#[test] +fn test_turn_into_index() { + let snippet = "hello world +Python is cool +Rust is cool +Go is cool +Ruby😂 is cool"; + let index = turn_into_index(snippet); + // assert_eq!(index[&0], vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + // assert_eq!(index[&0], vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + println!("done {:?}", index); + + // assert_eq!(get_from_index(&index, 0), 0); + let emoji_index = snippet.find("😂").unwrap(); + println!("{:?}", get_from_index(&index, emoji_index)); +} + // macro that generates the code for the different languages macro_rules! make_file { ($name:ident, $function:ident, $filtername:ident) => { @@ -212,9 +261,9 @@ macro_rules! make_file { } impl fmt::Display for $name { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for (index, func) in self.functions.iter().enumerate() { - write!( + write!( f, "{}", match index { diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 48242ba9..28060a41 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -285,9 +285,9 @@ pub(crate) fn find_function_in_file( .to_string(), lifetime: generics.1, generics: generics.0, - top: stuff.1 .0, - bottom: stuff.1 .1, - lines: (stuff.0 .0, stuff.0 .1), + top: stuff.1.0, + bottom: stuff.1.1, + lines: (stuff.0.0, stuff.0.1), return_type: function.ret_type().map(|ty| ty.to_string()), arguments: f.param_list().map_or_else(HashMap::new, |args| { args.params() @@ -307,13 +307,13 @@ pub(crate) fn find_function_in_file( } let attr = get_doc_comments_and_attrs(f); let start = stuff.0 .0; - let bb = match map[&start] { + let bb = match map[&(start-1)] { 0 => 0, x => x + 1, }; let contents: String = file_contents[bb..f.syntax().text_range().end().into()] .to_string(); - let body = super::make_lined(contents, start + 1); + let body = super::make_lined(contents, start); let function = RustFunction { name: f .name() @@ -360,19 +360,17 @@ fn get_stuff( block: &T, file: &str, map: &HashMap, -) -> ((usize, usize), (String, String), (usize, usize)) { +) -> ((usize, usize), (String, String)) { let start = block.syntax().text_range().start(); let end = block.syntax().text_range().end(); // get the start and end lines let mut found_start_brace = 0; let mut end_line = 0; - let mut starts = 0; let mut start_line = 0; // TODO: combine these loops for (i, line) in file.chars().enumerate() { if line == '\n' { if usize::from(start) < i { - starts = i; break; } start_line += 1; @@ -399,21 +397,21 @@ fn get_stuff( content = content[1..].to_string(); } ( - (start_line, end_line), + (start_line + 1, end_line), ( super::make_lined(content, start_lines + 1), super::make_lined( file.lines() .nth(if end_line == file.lines().count() - 1 { - end_line + end_line } else { - end_line - 1 + end_line }) .unwrap_or("").to_string(), - end_line, + end_line+1, ), ), - (starts, end_line), + // (starts, end_line), ) } #[inline] From b8839b1683e56301ad497200d1602ac01aad11fa Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Thu, 17 Nov 2022 01:02:29 -0500 Subject: [PATCH 133/172] ideas on why stuff could be broken --- git-function-history-lib/src/languages/mod.rs | 24 ++++++++++++------- .../src/test_functions.rs | 3 +++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 27e8c9f2..6961ffce 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -142,6 +142,8 @@ macro_rules! impl_function_trait { }; } // TODO: rewrite/fix this +// TODO: add a way for to compare the previous & next function tops & bottoms with the current functions individual tops & bottoms +// because two function in the same class or trait can have different parent functions etc, see output of the rust_parses test in the nested function part around line 18 - 53 pub fn fmt_with_context( current: &T, prev: Option<&T>, @@ -169,6 +171,7 @@ pub fn fmt_with_context( // println!("prev: {:?}, current {:?}", prev.get_total_lines(), current.get_total_lines()); if prev.get_total_lines() == current.get_total_lines() { write!(f, "{}", current.get_body())?; + write!(f, "{}", current.get_bottoms().into_iter().map(|x|format!("\n...\n{x}")).collect::())?; } else { write!(f, "{current}")?; } @@ -176,6 +179,7 @@ pub fn fmt_with_context( (None, Some(next)) => { // println!("current {:?}. next: {:?}", current.get_total_lines(), next.get_total_lines()); if next.get_total_lines() == current.get_total_lines() { + write!(f, "{}", current.get_tops().into_iter().map(|x|format!("{x}\n...\n")).collect::())?; write!(f, "{}", current.get_body())?; } else { write!(f, "{current}")?; @@ -352,19 +356,23 @@ make_file!(RubyFile, RubyFunction, Ruby); mod lang_tests { // macro that auto genertes the test parse__file_time macro_rules! make_file_time_test { - ($name:ident, $extname:ident, $function:ident) => { + ($name:ident, $extname:ident, $function:ident, $filetype:ident) => { #[test] fn $name() { let mut file = std::env::current_dir().unwrap(); file.push("src"); file.push("test_functions.".to_string() + stringify!($extname)); - let file = std::fs::read_to_string(file.clone()) + let files = std::fs::read_to_string(file.clone()) .expect(format!("could not read file {:?}", file).as_str()); let start = std::time::Instant::now(); - let ok = $function::find_function_in_file(&file, "empty_test"); + let ok = $function::find_function_in_file(&files, "empty_test"); let end = std::time::Instant::now(); match &ok { Ok(hist) => { + // turn the hist into a file + let file = $filetype::new(file.display().to_string(), hist.clone()); + println!("{}", file); + println!("-------------------"); for i in hist { println!("{}", i); println!("{:?}", i); @@ -381,11 +389,11 @@ mod lang_tests { } use super::*; - make_file_time_test!(python_parses, py, python); - make_file_time_test!(rust_parses, rs, rust); + make_file_time_test!(python_parses, py, python, PythonFile); + make_file_time_test!(rust_parses, rs, rust, RustFile); // #[cfg(feature = "c_lang")] - // make_file_time_test!(c_parses, c, c); + // make_file_time_test!(c_parses, c, c, CFile); #[cfg(feature = "unstable")] - make_file_time_test!(go_parses, go, go); - make_file_time_test!(ruby_parses, rb, ruby); + make_file_time_test!(go_parses, go, go, GoFile); + make_file_time_test!(ruby_parses, rb, ruby, RubyFile); } diff --git a/git-function-history-lib/src/test_functions.rs b/git-function-history-lib/src/test_functions.rs index 61b9372e..7929ccc0 100644 --- a/git-function-history-lib/src/test_functions.rs +++ b/git-function-history-lib/src/test_functions.rs @@ -27,6 +27,9 @@ impl
Test { } pub fn test_2() { + pub fn empty_test() { + println!("empty test"); + } println!("empty test"); // } } From 9c8b6a84038822fe97a4112ce4a4d2460b58ef59 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 17 Nov 2022 11:17:51 -0500 Subject: [PATCH 134/172] made examples/tests all compile/run --- git-function-history-lib/src/test_functions.c | 13 ++++++++++--- git-function-history-lib/src/test_functions.go | 6 +++--- git-function-history-lib/src/test_functions.py | 10 +++++++++- git-function-history-lib/src/test_functions.rs | 16 +++++++++++----- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/git-function-history-lib/src/test_functions.c b/git-function-history-lib/src/test_functions.c index 3eab266e..cb3910cb 100644 --- a/git-function-history-lib/src/test_functions.c +++ b/git-function-history-lib/src/test_functions.c @@ -2,18 +2,25 @@ void test_function(void); -void test_function2(void) +static void test_function2(void) { - printf("Hello World!" ); + printf("Hello World!"); + + // printf("Hello World!" ); } int main() { printf("Hello World!"); + test_function(); + test_function2(); + // test_functions(); + // test_functions2(); return 0; } void test_function(void) { printf("Hello World!"); -} \ No newline at end of file +} + diff --git a/git-function-history-lib/src/test_functions.go b/git-function-history-lib/src/test_functions.go index fc04e29a..b6966abc 100644 --- a/git-function-history-lib/src/test_functions.go +++ b/git-function-history-lib/src/test_functions.go @@ -2,15 +2,15 @@ package main import ( "fmt" - "os" ) func main() { - empty_test("1", 2, "3") + empty_test(1, 2, "3") fmt.Println("Hello World!") } + // doc comment func empty_test(c, a int, b string) { fmt.Println("Hello World!") -} \ No newline at end of file +} diff --git a/git-function-history-lib/src/test_functions.py b/git-function-history-lib/src/test_functions.py index a9ce9f17..a14517a7 100644 --- a/git-function-history-lib/src/test_functions.py +++ b/git-function-history-lib/src/test_functions.py @@ -5,6 +5,14 @@ # def empty_test(): # print("This is an empty test") +def assert_that(message): + def decorator(func): + def wrapper(*args, **kwargs): + print(message) + return func(*args, **kwargs) + return wrapper + return decorator + def test_with_assert(y, n,/,c=7, *, a , args, **kwargs): @assert_that("This is a test with an assert") def empty_test(t): @@ -15,7 +23,7 @@ def empty_test(t): class Test: pass passing_test = test_with_assert -@def_test +@assert_that("This is a test with an assert") def empty_test(n: int) -> list: """This is an empty test with a docstring""" pass diff --git a/git-function-history-lib/src/test_functions.rs b/git-function-history-lib/src/test_functions.rs index 7929ccc0..6d235b49 100644 --- a/git-function-history-lib/src/test_functions.rs +++ b/git-function-history-lib/src/test_functions.rs @@ -1,5 +1,5 @@ use std::error::Error; - +use std::fmt::Debug; pub fn empty_test() { } @@ -52,7 +52,7 @@ implTest { } } -#[derive(Debug)] + pub trait super_trait { fn super_trait_method(&self); @@ -124,7 +124,7 @@ super_trait { impl Test2 where A: super_trait + Clone, -T: super +A: Debug + Clone { pub fn empty_test<'a>() { @@ -133,7 +133,13 @@ T: super } +mod c { + extern "C" { + pub fn empty_test(t: String); + } +} -extern "C" { - pub fn empty_test(t: String); + +fn main() { + println!("Hello, world!"); } \ No newline at end of file From 6a4d9a15bbf5cbabfa2c26e115bd4ac23ad4afd4 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 17 Nov 2022 11:54:16 -0500 Subject: [PATCH 135/172] using turn into index/get into index fixes part of rust problem, removes some for loops/duplication --- git-function-history-lib/src/languages/go.rs | 35 +++------ git-function-history-lib/src/languages/mod.rs | 77 ++++++++++++++----- .../src/languages/python.rs | 13 ++-- .../src/languages/ruby.rs | 74 ++++-------------- .../src/languages/rust.rs | 36 +++------ 5 files changed, 100 insertions(+), 135 deletions(-) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index da97dd9a..2a42bd12 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -98,31 +98,16 @@ pub(crate) fn find_function_in_file( lines.0 = i.pos; } } - let mut body = file_contents[lines.0..=lines.1].to_string().trim_end().to_string(); - let mut start_line = 0; - for i in file_contents.chars().enumerate() { - if i.1 == '\n' { - if i.0 > lines.0 { - lines.0 = i.0; - break; - } - start_line += 1; - } - } - let mut end_line = 0; - for i in file_contents.chars().enumerate() { - if i.1 == '\n' { - if i.0 > lines.1 { - lines.1 = i.0; - break; - } - end_line += 1; - } - } - lines.0 = start_line + 1; - lines.1 = end_line + 1; - let start = start_line + 1; - body = super::make_lined(body, start); + let mut body = file_contents[lines.0..=lines.1] + .to_string() + .trim_end() + .to_string(); + let index = super::turn_into_index(file_contents); + lines.1 = super::get_from_index(&index, lines.1); + lines.0 = super::get_from_index(&index, lines.0); + // lines.0 = start_line + 1; + let start = lines.0; + body = super::make_lined(&body, start); // see if the first parameter has a name: let mut parameters = func.typ.params.list.get(0).map_or_else( || GoParameter::Type(vec![]), diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 6961ffce..b44e074b 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -1,7 +1,8 @@ use crate::Filter; use std::{ + collections::HashMap, error::Error, - fmt::{self, Display}, collections::HashMap, + fmt::{self, Display}, }; // TODO: lisp/scheme js, java?(https://github.com/tanin47/javaparser.rs) php?(https://docs.rs/tagua-parser/0.1.0/tagua_parser/) use self::{python::PythonFunction, ruby::RubyFunction, rust::RustFunction}; @@ -141,8 +142,8 @@ macro_rules! impl_function_trait { } }; } -// TODO: rewrite/fix this -// TODO: add a way for to compare the previous & next function tops & bottoms with the current functions individual tops & bottoms +// TODO: rewrite/fix this +// TODO: add a way for to compare the previous & next function tops & bottoms with the current functions individual tops & bottoms // because two function in the same class or trait can have different parent functions etc, see output of the rust_parses test in the nested function part around line 18 - 53 pub fn fmt_with_context( current: &T, @@ -159,9 +160,25 @@ pub fn fmt_with_context( write!(f, "{}", current.get_body())?; } else if prev.get_total_lines() == current.get_total_lines() { write!(f, "{}", current.get_body())?; - write!(f, "{}", current.get_bottoms().into_iter().map(|x|format!("\n...\n{x}")).collect::())?; + write!( + f, + "{}", + current + .get_bottoms() + .into_iter() + .map(|x| format!("\n...\n{x}")) + .collect::() + )?; } else if next.get_total_lines() == current.get_total_lines() { - write!(f, "{}", current.get_tops().into_iter().map(|x|format!("{x}\n...\n")).collect::())?; + write!( + f, + "{}", + current + .get_tops() + .into_iter() + .map(|x| format!("{x}\n...\n")) + .collect::() + )?; write!(f, "{}", current.get_body())?; } else { write!(f, "{current}")?; @@ -171,7 +188,15 @@ pub fn fmt_with_context( // println!("prev: {:?}, current {:?}", prev.get_total_lines(), current.get_total_lines()); if prev.get_total_lines() == current.get_total_lines() { write!(f, "{}", current.get_body())?; - write!(f, "{}", current.get_bottoms().into_iter().map(|x|format!("\n...\n{x}")).collect::())?; + write!( + f, + "{}", + current + .get_bottoms() + .into_iter() + .map(|x| format!("\n...\n{x}")) + .collect::() + )?; } else { write!(f, "{current}")?; } @@ -179,7 +204,15 @@ pub fn fmt_with_context( (None, Some(next)) => { // println!("current {:?}. next: {:?}", current.get_total_lines(), next.get_total_lines()); if next.get_total_lines() == current.get_total_lines() { - write!(f, "{}", current.get_tops().into_iter().map(|x|format!("{x}\n...\n")).collect::())?; + write!( + f, + "{}", + current + .get_tops() + .into_iter() + .map(|x| format!("{x}\n...\n")) + .collect::() + )?; write!(f, "{}", current.get_body())?; } else { write!(f, "{current}")?; @@ -194,11 +227,18 @@ pub fn fmt_with_context( Ok(()) } -fn make_lined(snippet: String, mut start: usize) -> String { - snippet.lines().map(|line| {let new = format!("{}: {}\n", start, line); - start += 1; - new -}).collect::().trim_end().to_string()} +fn make_lined(snippet: &str, mut start: usize) -> String { + snippet + .lines() + .map(|line| { + let new = format!("{start}: {line}\n"); + start += 1; + new + }) + .collect::() + .trim_end() + .to_string() +} pub trait FileTrait: fmt::Debug + fmt::Display { fn get_file_name(&self) -> String; @@ -217,8 +257,8 @@ fn turn_into_index(snippet: &str) -> HashMap> { let mut line: usize = 1; let mut char_index: usize = 0; for c in snippet.chars() { - println!("{}: {}", line, char_index); - println!("index: {:?}", index); + // println!("{}: {}", line, char_index); + // println!("index: {:?}", index); if c == '\n' { line += 1; index.insert(line, vec![char_index + 1]); @@ -226,7 +266,6 @@ fn turn_into_index(snippet: &str) -> HashMap> { index.get_mut(&line).unwrap().push(char_index); } char_index += c.len_utf8(); - } index @@ -247,10 +286,10 @@ Ruby😂 is cool"; let index = turn_into_index(snippet); // assert_eq!(index[&0], vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); // assert_eq!(index[&0], vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); - println!("done {:?}", index); + println!("done {index:?}"); // assert_eq!(get_from_index(&index, 0), 0); - let emoji_index = snippet.find("😂").unwrap(); + let emoji_index = snippet.find('😂').unwrap(); println!("{:?}", get_from_index(&index, emoji_index)); } @@ -265,9 +304,9 @@ macro_rules! make_file { } impl fmt::Display for $name { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for (index, func) in self.functions.iter().enumerate() { - write!( + write!( f, "{}", match index { diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 4386d7b0..bf20826b 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -134,7 +134,7 @@ pub(crate) fn find_function_in_file( let mut body = file_contents[*starts..*ends] .trim_start_matches('\n') .to_string(); - body = super::make_lined(body, start_s); + body = super::make_lined(&body, start_s); let class = func .1 .iter() @@ -153,7 +153,7 @@ pub(crate) fn find_function_in_file( None => return None, }; let top = format!("{start}: {top}"); - let decorators = get_decorator_list(decorator_list.clone()); + let decorators = get_decorator_list(decorator_list); return Some(PythonClass { name: name.to_string(), top, @@ -192,7 +192,7 @@ pub(crate) fn find_function_in_file( None => return None, }; let top = format!("{start}: {top}"); - let decorators = get_decorator_list(decorator_list.clone()); + let decorators = get_decorator_list(decorator_list); let parameters = get_args(*args.clone()); let returns = get_return_type(returns.clone()); return Some(PythonParentFunction { @@ -213,7 +213,7 @@ pub(crate) fn find_function_in_file( name: name.to_string(), parameters: get_args(*args), parent, - decorators: get_decorator_list(decorator_list), + decorators: get_decorator_list(&decorator_list), returns: get_return_type(returns), class, body, @@ -446,7 +446,7 @@ fn get_return_type(retr: Option>>) -> Option { None } -fn get_decorator_list(decorator_list: Vec>) -> Vec { +fn get_decorator_list(decorator_list: &[Located]) -> Vec { decorator_list .iter() .map(|x| x.node.name().to_string()) @@ -522,8 +522,7 @@ impl FunctionTrait for PythonFunction { fn get_total_lines(&self) -> (usize, usize) { // find the first line of the function (could be the parent or the class) - self - .class + self.class .iter() .map(|x| x.lines) .chain(self.parent.iter().map(|x| x.lines)) diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 2690b589..6f71623b 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -68,102 +68,58 @@ pub(crate) fn find_function_in_file( let parsed = parser.do_parse(); let ast = parsed.ast.unwrap_to_error("Failed to parse file")?; let fns = get_functions_from_node(&ast, &None, name); + let index = super::turn_into_index(file_contents); fns.iter() .map(|(f, c)| { let class = match c { Some(c) => { - let mut start_line = 0; - for i in file_contents.chars().enumerate() { - if i.1 == '\n' { - if i.0 > c.expression_l.begin { - break; - } - start_line += 1; - } - } - let mut end_line = 0; - for i in file_contents.chars().enumerate() { - if i.1 == '\n' { - if i.0 > c.expression_l.end { - break; - } - end_line += 1; - } - } + let start_line = super::get_from_index(&index, c.expression_l.begin); + let end_line = super::get_from_index(&index, c.expression_l.end); let loc_end = c.end_l; let top = Loc { begin: c.expression_l.begin, // TODO: check if there is a super class map_or to that - end: c.body.as_ref().map_or(c.keyword_l.end, |b| b.expression().begin), + end: c + .body + .as_ref() + .map_or(c.keyword_l.end, |b| b.expression().begin), }; let mut top = top .source(&parsed.input) .unwrap_to_error("Failed to get source")?; top = top.trim_end().to_string(); - top = super::make_lined(top, start_line+1); + top = super::make_lined(&top, start_line); Some(RubyClass { name: parser_class_name(c), line: (start_line, end_line), superclass: parse_superclass(c), - top: top, + top, bottom: super::make_lined( loc_end .source(&parsed.input) .unwrap_to_error("Failed to get source")? - .trim_matches('\n') - .to_string(), + .trim_matches('\n'), end_line, ), }) } None => None, }; - let mut start = f.expression_l.begin; + let start = f.expression_l.begin; // get the lines from map using f.expression_l.begin and f.expression_l.end - let mut start_line = 0; - for i in file_contents.chars().enumerate() { - if i.1 == '\n' { - if i.0 > f.expression_l.begin { - break; - } - start = i.0; - start_line += 1; - } - } - let mut end_line = 0; - for i in file_contents.chars().enumerate() { - if i.1 == '\n' { - if i.0 > f.expression_l.end { - break; - } - end_line += 1; - } - } + let start_line = super::get_from_index(&index, start); + let end_line = super::get_from_index(&index, f.expression_l.end); let starts = start_line + 1; Ok(RubyFunction { name: f.name.clone(), lines: (start_line + 1, end_line + 1), class, - body: - // f - // .expression_l - // .with_begin(start) - // .source(&parsed.input) - // .expect("Failed to get function body") - // .trim_matches('\n') - // .lines() - // .map(|l| { - // starts += 1; - // format!("{starts}: {l}\n",) - // }) - // .collect::().trim_end().to_string(), - super::make_lined( + body: super::make_lined( f.expression_l .with_begin(start) .source(&parsed.input) .expect("Failed to get function body") - .trim_matches('\n') - .to_string(), + .trim_matches('\n'), starts, ), args: f diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 28060a41..1a26369a 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -285,9 +285,9 @@ pub(crate) fn find_function_in_file( .to_string(), lifetime: generics.1, generics: generics.0, - top: stuff.1.0, - bottom: stuff.1.1, - lines: (stuff.0.0, stuff.0.1), + top: stuff.1 .0, + bottom: stuff.1 .1, + lines: (stuff.0 .0, stuff.0 .1), return_type: function.ret_type().map(|ty| ty.to_string()), arguments: f.param_list().map_or_else(HashMap::new, |args| { args.params() @@ -307,13 +307,12 @@ pub(crate) fn find_function_in_file( } let attr = get_doc_comments_and_attrs(f); let start = stuff.0 .0; - let bb = match map[&(start-1)] { + let bb = match map[&(start - 1)] { 0 => 0, x => x + 1, }; - let contents: String = file_contents[bb..f.syntax().text_range().end().into()] - .to_string(); - let body = super::make_lined(contents, start); + let contents: String = file_contents[bb..f.syntax().text_range().end().into()].to_string(); + let body = super::make_lined(&contents, start); let function = RustFunction { name: f .name() @@ -365,8 +364,9 @@ fn get_stuff( let end = block.syntax().text_range().end(); // get the start and end lines let mut found_start_brace = 0; - let mut end_line = 0; let mut start_line = 0; + let index = super::turn_into_index(file); + let end_line = super::get_from_index(&index, end.into()); // TODO: combine these loops for (i, line) in file.chars().enumerate() { if line == '\n' { @@ -377,14 +377,9 @@ fn get_stuff( } } for (i, line) in file.chars().enumerate() { - if line == '\n' { - if usize::from(end) < i { - break; - } - end_line += 1; - } if line == '{' && found_start_brace == 0 && usize::from(start) < i { found_start_brace = i; + break; } } if found_start_brace == 0 { @@ -399,17 +394,8 @@ fn get_stuff( ( (start_line + 1, end_line), ( - super::make_lined(content, start_lines + 1), - super::make_lined( - file.lines() - .nth(if end_line == file.lines().count() - 1 { - end_line - } else { - end_line - }) - .unwrap_or("").to_string(), - end_line+1, - ), + super::make_lined(&content, start_lines + 1), + super::make_lined(file.lines().nth(end_line - 1).unwrap_or(""), end_line), ), // (starts, end_line), ) From 6594da11b26f5db90c69476b550ebe988d281a5a Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 17 Nov 2022 15:13:02 -0500 Subject: [PATCH 136/172] IT ACTUALLY WORKS!!!! (wasnt menat to be in caps) --- git-function-history-lib/src/languages/go.rs | 8 ++++ git-function-history-lib/src/languages/mod.rs | 43 +++++++++++++++++++ .../src/languages/python.rs | 15 +++++++ .../src/languages/ruby.rs | 12 ++++++ .../src/languages/rust.rs | 22 ++++++++++ 5 files changed, 100 insertions(+) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index 2a42bd12..c59842f7 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -65,6 +65,14 @@ impl FunctionTrait for GoFunction { vec![] } + fn get_tops_with_line_numbers(&self) -> Vec<(String, usize)> { + vec![] + } + + fn get_bottoms_with_line_numbers(&self) -> Vec<(String, usize)> { + vec![] + } + fn get_total_lines(&self) -> (usize, usize) { let start = self.lines.0; let end = self.lines.1; diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index b44e074b..099bf616 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -124,6 +124,8 @@ pub trait FunctionTrait: fmt::Debug + fmt::Display { fn get_name(&self) -> String; fn get_bottoms(&self) -> Vec; fn get_body(&self) -> String; + fn get_tops_with_line_numbers(&self) -> Vec<(String, usize)>; + fn get_bottoms_with_line_numbers(&self) -> Vec<(String, usize)>; } // mace macro that generates get_lines, get_body,get_name @@ -145,6 +147,8 @@ macro_rules! impl_function_trait { // TODO: rewrite/fix this // TODO: add a way for to compare the previous & next function tops & bottoms with the current functions individual tops & bottoms // because two function in the same class or trait can have different parent functions etc, see output of the rust_parses test in the nested function part around line 18 - 53 +// proably either impl fmt::Display each file type outside the make_file macro and discard this function entirely +// where we save what tops & bottoms we have seen and compare them with the current functions tops & bottoms pub fn fmt_with_context( current: &T, prev: Option<&T>, @@ -226,6 +230,45 @@ pub fn fmt_with_context( } Ok(()) } +// TODO: puts this in make_file macro for fmt::Display +impl RustFile { + pub fn test_display(&self) -> String { + let mut str = String::new(); + // index of thef ile with no duplicates + let mut file: Vec<(String, usize)> = Vec::new(); + + for function in &self.functions { + // get the tops and their starting line number ie: parentfn.lines.0 + file.extend(function.get_tops_with_line_numbers()); + file.push((function.body.to_string(), function.get_lines().0)); + // get the bottoms and their end line number ie: parentfn.lines.1 + file.extend(function.get_bottoms_with_line_numbers()); + } + + file.sort_by(|a, b| a.1.cmp(&b.1)); + file.dedup(); + + // order the file by line number + file.sort_by(|a, b| a.1.cmp(&b.1)); + // print the file each element sperated by a \n...\n + for (i, (body, _)) in file.iter().enumerate() { + str.push_str(body); + if i != file.len() - 1 { + str.push_str("\n...\n"); + } + } + str + } +} + +#[test] +fn test_rust_file_display() { + let file = std::fs::read_to_string(r#"src\test_functions.rs"#).unwrap(); + let file = rust::find_function_in_file(&file, "empty_test").unwrap(); + let file = RustFile::new("".to_string(), file); + let file = file.test_display(); + println!("{file}"); +} fn make_lined(snippet: &str, mut start: usize) -> String { snippet diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index bf20826b..ee612e26 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -520,6 +520,21 @@ impl FunctionTrait for PythonFunction { tops } + fn get_tops_with_line_numbers(&self) -> Vec<(String, usize)> { + let mut tops = Vec::new(); + for class in &self.class { + tops.push((class.top.clone(), class.lines.0)); + } + for parent in &self.parent { + tops.push((parent.top.clone(), parent.lines.0)); + } + tops + } + + fn get_bottoms_with_line_numbers(&self) -> Vec<(String, usize)> { + Vec::new() + } + fn get_total_lines(&self) -> (usize, usize) { // find the first line of the function (could be the parent or the class) self.class diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 6f71623b..4a94cfa6 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -224,6 +224,18 @@ impl FunctionTrait for RubyFunction { fn get_total_lines(&self) -> (usize, usize) { self.class.as_ref().map_or(self.lines, |c| c.line) } + + fn get_tops_with_line_numbers(&self) -> Vec<(String, usize)> { + self.class + .as_ref() + .map_or_else(Vec::new, |c| vec![(c.top.clone(), c.line.0)]) + } + + fn get_bottoms_with_line_numbers(&self) -> Vec<(String, usize)> { + self.class + .as_ref() + .map_or_else(Vec::new, |c| vec![(c.bottom.clone(), c.line.1)]) + } } #[derive(Debug, Clone, PartialEq, Eq)] pub enum RubyFilter { diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 1a26369a..53496359 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -569,6 +569,28 @@ impl FunctionTrait for RustFunction { tops } + fn get_tops_with_line_numbers(&self) -> Vec<(String, usize)> { + let mut tops = Vec::new(); + self.block.as_ref().map_or((), |block| { + tops.push((block.top.clone(), block.lines.0)); + }); + for parent in &self.function { + tops.push((parent.top.clone(), parent.lines.0)); + } + tops + } + + fn get_bottoms_with_line_numbers(&self) -> Vec<(String, usize)> { + let mut bottoms = Vec::new(); + self.block.as_ref().map_or((), |block| { + bottoms.push((block.bottom.clone(), block.lines.1)); + }); + for parent in &self.function { + bottoms.push((parent.bottom.clone(), parent.lines.1)); + } + bottoms + } + fn get_total_lines(&self) -> (usize, usize) { self.block.as_ref().map_or_else( || { From e8c751fdb404598642c533768f83fd45115dbedf Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 17 Nov 2022 19:41:11 -0500 Subject: [PATCH 137/172] idk what iwas trying to do but i think fixed some stuff --- git-function-history-lib/src/languages/go.rs | 10 +- git-function-history-lib/src/languages/mod.rs | 95 ++++++------------- .../src/languages/python.rs | 1 + .../src/languages/ruby.rs | 12 ++- .../src/languages/rust.rs | 82 ++++++++-------- 5 files changed, 91 insertions(+), 109 deletions(-) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index c59842f7..07db7384 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -111,8 +111,14 @@ pub(crate) fn find_function_in_file( .trim_end() .to_string(); let index = super::turn_into_index(file_contents); - lines.1 = super::get_from_index(&index, lines.1); - lines.0 = super::get_from_index(&index, lines.0); + lines.1 = match super::get_from_index(&index, lines.1) { + Some(i) => i, + None => return None, + }; + lines.0 = match super::get_from_index(&index, lines.0) { + Some(i) => i, + None => return None, + }; // lines.0 = start_line + 1; let start = lines.0; body = super::make_lined(&body, start); diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 099bf616..00680707 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -144,11 +144,6 @@ macro_rules! impl_function_trait { } }; } -// TODO: rewrite/fix this -// TODO: add a way for to compare the previous & next function tops & bottoms with the current functions individual tops & bottoms -// because two function in the same class or trait can have different parent functions etc, see output of the rust_parses test in the nested function part around line 18 - 53 -// proably either impl fmt::Display each file type outside the make_file macro and discard this function entirely -// where we save what tops & bottoms we have seen and compare them with the current functions tops & bottoms pub fn fmt_with_context( current: &T, prev: Option<&T>, @@ -230,45 +225,6 @@ pub fn fmt_with_context( } Ok(()) } -// TODO: puts this in make_file macro for fmt::Display -impl RustFile { - pub fn test_display(&self) -> String { - let mut str = String::new(); - // index of thef ile with no duplicates - let mut file: Vec<(String, usize)> = Vec::new(); - - for function in &self.functions { - // get the tops and their starting line number ie: parentfn.lines.0 - file.extend(function.get_tops_with_line_numbers()); - file.push((function.body.to_string(), function.get_lines().0)); - // get the bottoms and their end line number ie: parentfn.lines.1 - file.extend(function.get_bottoms_with_line_numbers()); - } - - file.sort_by(|a, b| a.1.cmp(&b.1)); - file.dedup(); - - // order the file by line number - file.sort_by(|a, b| a.1.cmp(&b.1)); - // print the file each element sperated by a \n...\n - for (i, (body, _)) in file.iter().enumerate() { - str.push_str(body); - if i != file.len() - 1 { - str.push_str("\n...\n"); - } - } - str - } -} - -#[test] -fn test_rust_file_display() { - let file = std::fs::read_to_string(r#"src\test_functions.rs"#).unwrap(); - let file = rust::find_function_in_file(&file, "empty_test").unwrap(); - let file = RustFile::new("".to_string(), file); - let file = file.test_display(); - println!("{file}"); -} fn make_lined(snippet: &str, mut start: usize) -> String { snippet @@ -296,27 +252,27 @@ fn turn_into_index(snippet: &str) -> HashMap> { // turn snippet into a hashmap of line number to char index // so line 1 is 0 to 10, line 2 is 11 to 20, etc let mut index = HashMap::new(); - index.insert(1, vec![0]); + index.insert(1, vec![]); let mut line: usize = 1; let mut char_index: usize = 0; for c in snippet.chars() { - // println!("{}: {}", line, char_index); - // println!("index: {:?}", index); if c == '\n' { line += 1; - index.insert(line, vec![char_index + 1]); + index.insert(line, vec![char_index]); } else { index.get_mut(&line).unwrap().push(char_index); } char_index += c.len_utf8(); } - index } -fn get_from_index(index: &HashMap>, char: usize) -> usize { +fn get_from_index(index: &HashMap>, char: usize) -> Option { // gets the line number from the index - *index.iter().find(|(_, v)| v.contains(&char)).unwrap().0 + index + .iter() + .find(|(_, v)| v.contains(&char)) + .map(|(k, _)| *k) } #[test] @@ -348,21 +304,28 @@ macro_rules! make_file { impl fmt::Display for $name { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for (index, func) in self.functions.iter().enumerate() { - write!( - f, - "{}", - match index { - 0 => "", - _ => "\n...\n", - }, - )?; - let previous = match index { - 0 => None, - _ => Some(&self.functions[index - 1]), - }; - let next = self.functions.get(index + 1); - crate::languages::fmt_with_context(func, previous, next, f)?; + let mut file: Vec<(String, usize)> = Vec::new(); + + for function in &self.functions { + // get the tops and their starting line number ie: parentfn.lines.0 + file.extend(function.get_tops_with_line_numbers()); + file.push((function.body.to_string(), function.get_lines().0)); + // get the bottoms and their end line number ie: parentfn.lines.1 + file.extend(function.get_bottoms_with_line_numbers()); + } + + file.sort_by(|a, b| a.1.cmp(&b.1)); + file.dedup(); + + // order the file by line number + file.sort_by(|a, b| a.1.cmp(&b.1)); + // print the file each element sperated by a \n...\n + for (i, (body, _)) in file.iter().enumerate() { + // str.push_str(body); + write!(f, "{}", body)?; + if i != file.len() - 1 { + write!(f, "\n...\n")?; + } } Ok(()) } diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index ee612e26..0233ab9e 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -509,6 +509,7 @@ impl PythonFilter { } impl FunctionTrait for PythonFunction { + // TODO: return decorator list too fn get_tops(&self) -> Vec { let mut tops = Vec::new(); for class in &self.class { diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 4a94cfa6..8567b2da 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -73,8 +73,10 @@ pub(crate) fn find_function_in_file( .map(|(f, c)| { let class = match c { Some(c) => { - let start_line = super::get_from_index(&index, c.expression_l.begin); - let end_line = super::get_from_index(&index, c.expression_l.end); + let start_line = super::get_from_index(&index, c.expression_l.begin) + .unwrap_to_error("Failed to get start line")?; + let end_line = super::get_from_index(&index, c.expression_l.end) + .unwrap_to_error("Failed to get end line")?; let loc_end = c.end_l; let top = Loc { begin: c.expression_l.begin, @@ -107,8 +109,10 @@ pub(crate) fn find_function_in_file( }; let start = f.expression_l.begin; // get the lines from map using f.expression_l.begin and f.expression_l.end - let start_line = super::get_from_index(&index, start); - let end_line = super::get_from_index(&index, f.expression_l.end); + let start_line = + super::get_from_index(&index, start).unwrap_to_error("Failed to get start line")?; + let end_line = super::get_from_index(&index, f.expression_l.end) + .unwrap_to_error("Failed to get end line")?; let starts = start_line + 1; Ok(RubyFunction { name: f.name.clone(), diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 53496359..eb877f8c 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -5,7 +5,7 @@ use ra_ap_syntax::{ AstNode, SourceFile, SyntaxKind, }; -use crate::impl_function_trait; +use crate::{impl_function_trait, UnwrapToError}; use super::FunctionTrait; @@ -217,7 +217,7 @@ pub(crate) fn find_function_in_file( .collect::>(); let mut hist = Vec::new(); for f in &functions { - let stuff = get_stuff(f, file_contents, &map); + let stuff = get_stuff(f, file_contents, &map).unwrap_to_error("could not get endline")?; let generics = get_genrerics_and_lifetime(f); let mut parent = f.syntax().parent(); let mut parent_fn: Vec = Vec::new(); @@ -230,7 +230,12 @@ pub(crate) fn find_function_in_file( || { if let Some(block) = ast::Impl::cast(p.clone()) { let attr = get_doc_comments_and_attrs(&block); - let stuff = get_stuff(&block, file_contents, &map); + let stuff = match get_stuff(&block, file_contents, &map) { + Some(s) => s, + None => { + return; + } + }; let generics = get_genrerics_and_lifetime(&block); parent_block = Some(Block { name: block.self_ty().map(|ty| ty.to_string()), @@ -245,7 +250,12 @@ pub(crate) fn find_function_in_file( }); } else if let Some(block) = ast::Trait::cast(p.clone()) { let attr = get_doc_comments_and_attrs(&block); - let stuff = get_stuff(&block, file_contents, &map); + let stuff = match get_stuff(&block, file_contents, &map) { + Some(s) => s, + None => { + return; + } + }; let generics = get_genrerics_and_lifetime(&block); parent_block = Some(Block { name: block.name().map(|ty| ty.to_string()), @@ -261,21 +271,29 @@ pub(crate) fn find_function_in_file( } else if let Some(block) = ast::ExternBlock::cast(p.clone()) { let attr = get_doc_comments_and_attrs(&block); let stuff = get_stuff(&block, file_contents, &map); - parent_block = Some(Block { - name: block.abi().map(|ty| ty.to_string()), - lifetime: Vec::new(), - generics: Vec::new(), - top: stuff.1 .0, - bottom: stuff.1 .1, - block_type: BlockType::Extern, - lines: (stuff.0 .0, stuff.0 .1), - attributes: attr.1, - doc_comments: attr.0, - }); + if let Some(stuff) = stuff { + parent_block = Some(Block { + name: None, + lifetime: Vec::new(), + generics: Vec::new(), + top: stuff.1 .0, + bottom: stuff.1 .1, + block_type: BlockType::Extern, + lines: (stuff.0 .0, stuff.0 .1), + attributes: attr.1, + doc_comments: attr.0, + }); + } } }, - |function| { - let stuff = get_stuff(&function, file_contents, &map); + |function: ast::Fn| { + let stuff = match get_stuff(&function, file_contents, &map) { + Some(value) => value, + None => { + return; + } + }; + let generics = get_genrerics_and_lifetime(&function); let attr = get_doc_comments_and_attrs(&function); parent_fn.push(RustParentFunction { @@ -359,23 +377,14 @@ fn get_stuff( block: &T, file: &str, map: &HashMap, -) -> ((usize, usize), (String, String)) { +) -> Option<((usize, usize), (String, String))> { let start = block.syntax().text_range().start(); - let end = block.syntax().text_range().end(); + let end: usize = block.syntax().text_range().end().into(); // get the start and end lines let mut found_start_brace = 0; - let mut start_line = 0; let index = super::turn_into_index(file); - let end_line = super::get_from_index(&index, end.into()); - // TODO: combine these loops - for (i, line) in file.chars().enumerate() { - if line == '\n' { - if usize::from(start) < i { - break; - } - start_line += 1; - } - } + let end_line = super::get_from_index(&index, end - 1)?; + let start_line = super::get_from_index(&index, start.into())?; for (i, line) in file.chars().enumerate() { if line == '{' && found_start_brace == 0 && usize::from(start) < i { found_start_brace = i; @@ -385,20 +394,19 @@ fn get_stuff( if found_start_brace == 0 { found_start_brace = usize::from(start); } - let start = map[&start_line]; + let start = map[&(start_line - 1)]; let start_lines = start_line; let mut content: String = file[(*start)..=found_start_brace].to_string(); if &content[..1] == "\n" { content = content[1..].to_string(); } - ( - (start_line + 1, end_line), + Some(( + (start_line, end_line), ( - super::make_lined(&content, start_lines + 1), - super::make_lined(file.lines().nth(end_line - 1).unwrap_or(""), end_line), + super::make_lined(&content, start_lines), + super::make_lined(file.lines().nth(end_line - 1).unwrap_or("}"), end_line), ), - // (starts, end_line), - ) + )) } #[inline] fn get_genrerics_and_lifetime(block: &T) -> (Vec, Vec) { From c648d987734442f74ddc307c3a7b747dd22b567a Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Tue, 22 Nov 2022 16:15:55 -0500 Subject: [PATCH 138/172] updated dependncies --- cargo-function-history/Cargo.toml | 6 +++--- git-function-history-gui/Cargo.toml | 2 +- git-function-history-lib/Cargo.toml | 14 +++++++------- git-function-history-lib/src/lib.rs | 12 ++++++------ 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/cargo-function-history/Cargo.toml b/cargo-function-history/Cargo.toml index fe13a360..58407e67 100644 --- a/cargo-function-history/Cargo.toml +++ b/cargo-function-history/Cargo.toml @@ -21,10 +21,10 @@ git_function_history = { path = "../git-function-history-lib", version = "0.6.2" lazy_static = "1.4.0" tui = { version = "0.19", features = ["crossterm"], default-features = false } crossterm = "0.25.0" -tokio = { version = "1.21.2", features = ["full"] } -eyre = "0.6" +tokio = { version = "1.22.0", features = ["full"] } +eyre = "0.6.8" dirs = "4.0.0" simple_file_logger = "0.2.0" -log = "0.4" +log = "0.4.17" function_history_backend_thread = { path = "../function_history_backend_thread", version = "0.2.2", default-features = false} tui-input = "0.6.1" \ No newline at end of file diff --git a/git-function-history-gui/Cargo.toml b/git-function-history-gui/Cargo.toml index fdc851e2..51b30440 100644 --- a/git-function-history-gui/Cargo.toml +++ b/git-function-history-gui/Cargo.toml @@ -22,4 +22,4 @@ git_function_history = { path = "../git-function-history-lib", version = "0.6.2" function_history_backend_thread = { path = "../function_history_backend_thread", version = "0.2.2", default-features = false} simple_file_logger = "0.2.0" log = "0.4.17" -image = "0.24.4" \ No newline at end of file +image = "0.24.5" \ No newline at end of file diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 6c649de9..2615924e 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -17,18 +17,18 @@ unstable = ["dep:gosyn"] cache = ["dep:cached"] [dependencies] -chrono = "0.4.22" -ra_ap_syntax = "0.0.138" -rayon = { version = "1.5.3", optional = true } +chrono = "0.4.23" +ra_ap_syntax = "0.0.140" +rayon = { version = "1.6.0", optional = true } # rustpython-parser = "0.1.2" # for end_lines but can't be publsihed b/c git depenency -rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb" } +rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "f885db8c61514f069979861f6b3bd83292086231" } lib-ruby-parser = "3.0.12" gosyn = {version = "0.2.0", optional = true} # can't be published b/c git dependency # javaparser = {git = "https://github.com/tanin47/javaparser.rs", optional = true} cfg-if = "1.0.0" cached = {version = "0.40.0", optional = true} -gitoxide-core = "0.19.0" -git-repository = { version = "0.27.0", default-features = false, features = ["max-performance-safe"] } -git-features = { version = "0.23.1", features = ["zlib", "once_cell"] } \ No newline at end of file +gitoxide-core = "0.21.0" +git-repository = { version = "0.29.0", default-features = false, features = ["max-performance-safe"] } +git-features = { version = "0.24.0", features = ["zlib", "once_cell"] } \ No newline at end of file diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 711bb405..26b81e81 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -193,7 +193,7 @@ pub fn get_function_history( let tree = i.tree().ok()?.id; let time = i.time().ok()?; let time = DateTime::::from_utc( - NaiveDateTime::from_timestamp(time.seconds_since_unix_epoch.into(), 0), + NaiveDateTime::from_timestamp_opt(time.seconds_since_unix_epoch.into(), 0)?, Utc, ); let authorinfo = i.author().ok()?; @@ -474,13 +474,13 @@ pub fn get_git_info() -> Result, Box> { Some(CommitInfo { date: match i.time().map(|x| { - DateTime::::from_utc( - NaiveDateTime::from_timestamp(x.seconds_since_unix_epoch.into(), 0), + Some(DateTime::::from_utc( + NaiveDateTime::from_timestamp_opt(x.seconds_since_unix_epoch.into(), 0)?, Utc, - ) + )) }) { - Ok(i) => i, - Err(_) => return None, + Ok(Some(i)) => i, + _ => return None, }, hash: i.id.to_string(), author_email: author.email.to_string(), From 7d5e82ef4bc7bc2bccc296d01fb2b8a22c1a5e90 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Tue, 22 Nov 2022 21:16:31 +0000 Subject: [PATCH 139/172] update changelog --- CHANGELOG.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08913564..aff25751 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,10 +28,7 @@ All notable changes to this project will be documented in this file. ### Lib -- Moved away from using mostly enerics to using enums - Python works besides for one edge case when the function is the last node -- Non proggraming languge (pl) filters addded back -- Added ability to search in all supported languages - Pl filters now working very messy and boilerplatety - Fixed bug where I didnt understand how cfg-if works, also filter_by macro works just neeeds docs @@ -39,14 +36,12 @@ All notable changes to this project will be documented in this file. - Saving search history to a file now - Shortend filter loc -- Search/filters are fixed was not working b/c of using window(2) - Added more filters ## [2.1.0] - 2022-09-28 ### Library -- Added git filters for commit, aothor and emai, messagel - More parllesim - Trying to optimize threading realizng the problem is not with the trreading but with something else - Added parelel as optinal (but default feature From 2984fe39e7b62957b72c38bb1f59e9a62b915372 Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Thu, 24 Nov 2022 00:12:37 -0500 Subject: [PATCH 140/172] did a lot of clean + let..else etc --- git-function-history-lib/src/languages/go.rs | 12 +- git-function-history-lib/src/languages/mod.rs | 103 ++---------------- .../src/languages/python.rs | 21 +--- .../src/languages/ruby.rs | 16 +-- .../src/languages/rust.rs | 49 ++------- git-function-history-lib/src/lib.rs | 10 +- git-function-history-lib/src/types.rs | 10 +- 7 files changed, 29 insertions(+), 192 deletions(-) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index 07db7384..53872d20 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -57,19 +57,11 @@ impl fmt::Display for GoFunction { impl FunctionTrait for GoFunction { impl_function_trait!(GoFunction); - fn get_bottoms(&self) -> Vec { + fn get_tops(&self) -> Vec<(String, usize)> { vec![] } - fn get_tops(&self) -> Vec { - vec![] - } - - fn get_tops_with_line_numbers(&self) -> Vec<(String, usize)> { - vec![] - } - - fn get_bottoms_with_line_numbers(&self) -> Vec<(String, usize)> { + fn get_bottoms(&self) -> Vec<(String, usize)> { vec![] } diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 00680707..4a7041f5 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -2,7 +2,7 @@ use crate::Filter; use std::{ collections::HashMap, error::Error, - fmt::{self, Display}, + fmt::{self}, }; // TODO: lisp/scheme js, java?(https://github.com/tanin47/javaparser.rs) php?(https://docs.rs/tagua-parser/0.1.0/tagua_parser/) use self::{python::PythonFunction, ruby::RubyFunction, rust::RustFunction}; @@ -118,14 +118,16 @@ pub mod ruby; pub mod rust; pub trait FunctionTrait: fmt::Debug + fmt::Display { - fn get_tops(&self) -> Vec; fn get_lines(&self) -> (usize, usize); fn get_total_lines(&self) -> (usize, usize); fn get_name(&self) -> String; - fn get_bottoms(&self) -> Vec; fn get_body(&self) -> String; - fn get_tops_with_line_numbers(&self) -> Vec<(String, usize)>; - fn get_bottoms_with_line_numbers(&self) -> Vec<(String, usize)>; + /// returns the tops like any the heading of classes/impls (among others) the function is part of along with the starting line of each heading + /// for example it could return `[("impl Test {", 3)]` + /// to get just for example the headings use the map method `function.get_tops().map(|top| top.0)` + fn get_tops(&self) -> Vec<(String, usize)>; + /// same as `get_tops` just retrieves the bottoms like so `[("}", 22)]` + fn get_bottoms(&self) -> Vec<(String, usize)>; } // mace macro that generates get_lines, get_body,get_name @@ -144,87 +146,6 @@ macro_rules! impl_function_trait { } }; } -pub fn fmt_with_context( - current: &T, - prev: Option<&T>, - next: Option<&T>, - f: &mut fmt::Formatter<'_>, -) -> fmt::Result { - match (prev, next) { - (Some(prev), Some(next)) => { - // println!("prev: {:?}, current {:?}. next: {:?}", prev.get_total_lines(), current.get_total_lines(), next.get_total_lines()); - if prev.get_total_lines() == current.get_total_lines() - && next.get_total_lines() == current.get_total_lines() - { - write!(f, "{}", current.get_body())?; - } else if prev.get_total_lines() == current.get_total_lines() { - write!(f, "{}", current.get_body())?; - write!( - f, - "{}", - current - .get_bottoms() - .into_iter() - .map(|x| format!("\n...\n{x}")) - .collect::() - )?; - } else if next.get_total_lines() == current.get_total_lines() { - write!( - f, - "{}", - current - .get_tops() - .into_iter() - .map(|x| format!("{x}\n...\n")) - .collect::() - )?; - write!(f, "{}", current.get_body())?; - } else { - write!(f, "{current}")?; - } - } - (Some(prev), None) => { - // println!("prev: {:?}, current {:?}", prev.get_total_lines(), current.get_total_lines()); - if prev.get_total_lines() == current.get_total_lines() { - write!(f, "{}", current.get_body())?; - write!( - f, - "{}", - current - .get_bottoms() - .into_iter() - .map(|x| format!("\n...\n{x}")) - .collect::() - )?; - } else { - write!(f, "{current}")?; - } - } - (None, Some(next)) => { - // println!("current {:?}. next: {:?}", current.get_total_lines(), next.get_total_lines()); - if next.get_total_lines() == current.get_total_lines() { - write!( - f, - "{}", - current - .get_tops() - .into_iter() - .map(|x| format!("{x}\n...\n")) - .collect::() - )?; - write!(f, "{}", current.get_body())?; - } else { - write!(f, "{current}")?; - } - } - (None, None) => { - // println!("current {:?}", current.get_total_lines()); - // print the function - write!(f, "{current}")?; - } - } - Ok(()) -} fn make_lined(snippet: &str, mut start: usize) -> String { snippet @@ -305,23 +226,19 @@ macro_rules! make_file { impl fmt::Display for $name { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut file: Vec<(String, usize)> = Vec::new(); - for function in &self.functions { // get the tops and their starting line number ie: parentfn.lines.0 - file.extend(function.get_tops_with_line_numbers()); + file.extend(function.get_tops()); file.push((function.body.to_string(), function.get_lines().0)); // get the bottoms and their end line number ie: parentfn.lines.1 - file.extend(function.get_bottoms_with_line_numbers()); + file.extend(function.get_bottoms()); } - file.sort_by(|a, b| a.1.cmp(&b.1)); file.dedup(); - // order the file by line number file.sort_by(|a, b| a.1.cmp(&b.1)); // print the file each element sperated by a \n...\n for (i, (body, _)) in file.iter().enumerate() { - // str.push_str(body); write!(f, "{}", body)?; if i != file.len() - 1 { write!(f, "\n...\n")?; @@ -348,7 +265,7 @@ macro_rules! make_file { if let Filter::PLFilter(LanguageFilter::$filtername(_)) | Filter::FunctionInLines(..) = filter { - } else if let Filter::None = filter { + } else if matches!(filter, Filter::None) { return Ok(self.clone()); } else { return Err("filter not supported for this type")?; diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 0233ab9e..787272a2 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -447,6 +447,7 @@ fn get_return_type(retr: Option>>) -> Option { } fn get_decorator_list(decorator_list: &[Located]) -> Vec { + // todo add full test version ie not just name and also add line numbers so it can be displayed/retrieved with get_tops decorator_list .iter() .map(|x| x.node.name().to_string()) @@ -510,18 +511,7 @@ impl PythonFilter { impl FunctionTrait for PythonFunction { // TODO: return decorator list too - fn get_tops(&self) -> Vec { - let mut tops = Vec::new(); - for class in &self.class { - tops.push(class.top.clone()); - } - for parent in &self.parent { - tops.push(parent.top.clone()); - } - tops - } - - fn get_tops_with_line_numbers(&self) -> Vec<(String, usize)> { + fn get_tops(&self) -> Vec<(String, usize)> { let mut tops = Vec::new(); for class in &self.class { tops.push((class.top.clone(), class.lines.0)); @@ -532,7 +522,7 @@ impl FunctionTrait for PythonFunction { tops } - fn get_bottoms_with_line_numbers(&self) -> Vec<(String, usize)> { + fn get_bottoms(&self) -> Vec<(String, usize)> { Vec::new() } @@ -545,10 +535,5 @@ impl FunctionTrait for PythonFunction { .min() .unwrap_or(self.lines) } - - fn get_bottoms(&self) -> Vec { - // in python there is no bottom - Vec::new() - } impl_function_trait!(PythonFunction); } diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 8567b2da..6c49803c 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -213,29 +213,17 @@ fn parse_superclass(class: &Class) -> Option { impl FunctionTrait for RubyFunction { crate::impl_function_trait!(RubyFunction); - fn get_tops(&self) -> Vec { - self.class - .as_ref() - .map_or_else(Vec::new, |c| vec![c.top.clone()]) - } - - fn get_bottoms(&self) -> Vec { - self.class - .as_ref() - .map_or_else(Vec::new, |c| vec![c.bottom.clone()]) - } - fn get_total_lines(&self) -> (usize, usize) { self.class.as_ref().map_or(self.lines, |c| c.line) } - fn get_tops_with_line_numbers(&self) -> Vec<(String, usize)> { + fn get_tops(&self) -> Vec<(String, usize)> { self.class .as_ref() .map_or_else(Vec::new, |c| vec![(c.top.clone(), c.line.0)]) } - fn get_bottoms_with_line_numbers(&self) -> Vec<(String, usize)> { + fn get_bottoms(&self) -> Vec<(String, usize)> { self.class .as_ref() .map_or_else(Vec::new, |c| vec![(c.bottom.clone(), c.line.1)]) diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index eb877f8c..5fec07de 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -230,11 +230,8 @@ pub(crate) fn find_function_in_file( || { if let Some(block) = ast::Impl::cast(p.clone()) { let attr = get_doc_comments_and_attrs(&block); - let stuff = match get_stuff(&block, file_contents, &map) { - Some(s) => s, - None => { - return; - } + let Some(stuff) = get_stuff(&block, file_contents, &map) else { + return; }; let generics = get_genrerics_and_lifetime(&block); parent_block = Some(Block { @@ -250,11 +247,8 @@ pub(crate) fn find_function_in_file( }); } else if let Some(block) = ast::Trait::cast(p.clone()) { let attr = get_doc_comments_and_attrs(&block); - let stuff = match get_stuff(&block, file_contents, &map) { - Some(s) => s, - None => { - return; - } + let Some(stuff) = get_stuff(&block, file_contents, &map) else { + return; }; let generics = get_genrerics_and_lifetime(&block); parent_block = Some(Block { @@ -287,13 +281,9 @@ pub(crate) fn find_function_in_file( } }, |function: ast::Fn| { - let stuff = match get_stuff(&function, file_contents, &map) { - Some(value) => value, - None => { - return; - } + let Some(stuff) = get_stuff(&function, file_contents, &map) else { + return; }; - let generics = get_genrerics_and_lifetime(&function); let attr = get_doc_comments_and_attrs(&function); parent_fn.push(RustParentFunction { @@ -566,18 +556,7 @@ impl RustFilter { } impl FunctionTrait for RustFunction { - fn get_tops(&self) -> Vec { - let mut tops = Vec::new(); - self.block.as_ref().map_or((), |block| { - tops.push(block.top.clone()); - }); - for parent in &self.function { - tops.push(parent.top.clone()); - } - tops - } - - fn get_tops_with_line_numbers(&self) -> Vec<(String, usize)> { + fn get_tops(&self) -> Vec<(String, usize)> { let mut tops = Vec::new(); self.block.as_ref().map_or((), |block| { tops.push((block.top.clone(), block.lines.0)); @@ -588,7 +567,7 @@ impl FunctionTrait for RustFunction { tops } - fn get_bottoms_with_line_numbers(&self) -> Vec<(String, usize)> { + fn get_bottoms(&self) -> Vec<(String, usize)> { let mut bottoms = Vec::new(); self.block.as_ref().map_or((), |block| { bottoms.push((block.bottom.clone(), block.lines.1)); @@ -616,17 +595,5 @@ impl FunctionTrait for RustFunction { ) } - fn get_bottoms(&self) -> Vec { - let mut bottoms = Vec::new(); - - for parent in &self.function { - bottoms.push(parent.bottom.clone()); - } - self.block.as_ref().map_or((), |block| { - bottoms.push(block.bottom.clone()); - }); - bottoms - } - impl_function_trait!(RustFunction); } diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 26b81e81..06e59633 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -459,14 +459,8 @@ pub fn get_git_info() -> Result, Box> { let commit_iter = repo.rev_walk(tips); let commits = commit_iter.all()?.filter_map(|i| match i { Ok(i) => get_item_from_oid_option!(i, &repo, try_into_commit).map(|i| { - let author = match i.author() { - Ok(author) => author, - Err(_) => return None, - }; - let message = match i.message() { - Ok(message) => message, - Err(_) => return None, - }; + let Ok(author) = i.author() else { return None }; + let Ok(message) = i.message() else { return None }; let mut msg = message.title.to_string(); if let Some(msg_body) = message.body { msg.push_str(&msg_body.to_string()); diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 29f311c6..7dc41e52 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -398,14 +398,8 @@ impl FunctionHistory { } } Filter::DateRange(start, end) => { - let start = match DateTime::parse_from_rfc2822(start) { - Ok(date) => date, - Err(_) => return None, - }; - let end = match DateTime::parse_from_rfc2822(end) { - Ok(date) => date, - Err(_) => return None, - }; + let Ok(start) = DateTime::parse_from_rfc2822(start) else { return None }; + let Ok(end) = DateTime::parse_from_rfc2822(end) else { return None }; if f.date >= start || f.date <= end { Some(f.clone()) } else { From ce0961c2b8600aa90f2fdbd9925e0754e20d6373 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Thu, 24 Nov 2022 14:19:13 +0000 Subject: [PATCH 141/172] update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aff25751..08913564 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,10 @@ All notable changes to this project will be documented in this file. ### Lib +- Moved away from using mostly enerics to using enums - Python works besides for one edge case when the function is the last node +- Non proggraming languge (pl) filters addded back +- Added ability to search in all supported languages - Pl filters now working very messy and boilerplatety - Fixed bug where I didnt understand how cfg-if works, also filter_by macro works just neeeds docs @@ -36,12 +39,14 @@ All notable changes to this project will be documented in this file. - Saving search history to a file now - Shortend filter loc +- Search/filters are fixed was not working b/c of using window(2) - Added more filters ## [2.1.0] - 2022-09-28 ### Library +- Added git filters for commit, aothor and emai, messagel - More parllesim - Trying to optimize threading realizng the problem is not with the trreading but with something else - Added parelel as optinal (but default feature From f22dff5495382d60f8b1440711fd2698e6aeedf1 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Thu, 1 Dec 2022 22:19:49 -0500 Subject: [PATCH 142/172] useing new logger macro --- cargo-function-history/Cargo.toml | 2 +- cargo-function-history/src/main.rs | 2 +- git-function-history-gui/Cargo.toml | 2 +- git-function-history-gui/src/main.rs | 8 ++------ git-function-history-lib/src/lib.rs | 4 ++-- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/cargo-function-history/Cargo.toml b/cargo-function-history/Cargo.toml index 58407e67..78f61f15 100644 --- a/cargo-function-history/Cargo.toml +++ b/cargo-function-history/Cargo.toml @@ -24,7 +24,7 @@ crossterm = "0.25.0" tokio = { version = "1.22.0", features = ["full"] } eyre = "0.6.8" dirs = "4.0.0" -simple_file_logger = "0.2.0" +simple_file_logger = "0.3.1" log = "0.4.17" function_history_backend_thread = { path = "../function_history_backend_thread", version = "0.2.2", default-features = false} tui-input = "0.6.1" \ No newline at end of file diff --git a/cargo-function-history/src/main.rs b/cargo-function-history/src/main.rs index f6e83a9d..eca1d556 100644 --- a/cargo-function-history/src/main.rs +++ b/cargo-function-history/src/main.rs @@ -6,7 +6,7 @@ use git_function_history::{FileFilterType, Filter}; use log::info; fn main() -> Result<(), Box> { - simple_file_logger::init_logger("cargo_function_history", simple_file_logger::LogLevel::Info)?; + simple_file_logger::init_logger!("cargo_function_history")?; info!("Starting cargo function history"); let (tx_t, rx_m) = mpsc::channel(); let (tx_m, rx_t) = mpsc::channel(); diff --git a/git-function-history-gui/Cargo.toml b/git-function-history-gui/Cargo.toml index 51b30440..dfb92b7c 100644 --- a/git-function-history-gui/Cargo.toml +++ b/git-function-history-gui/Cargo.toml @@ -20,6 +20,6 @@ unstable = ["git_function_history/unstable", "function_history_backend_thread/un eframe = {version = "0.19.0", features = ["dark-light"]} git_function_history = { path = "../git-function-history-lib", version = "0.6.2", default-features = false} function_history_backend_thread = { path = "../function_history_backend_thread", version = "0.2.2", default-features = false} -simple_file_logger = "0.2.0" +simple_file_logger = "0.3.1" log = "0.4.17" image = "0.24.5" \ No newline at end of file diff --git a/git-function-history-gui/src/main.rs b/git-function-history-gui/src/main.rs index 8430cba6..c71288bf 100644 --- a/git-function-history-gui/src/main.rs +++ b/git-function-history-gui/src/main.rs @@ -5,12 +5,8 @@ use std::sync::mpsc; fn main() { let (tx_t, rx_m) = mpsc::channel(); let (tx_m, rx_t) = mpsc::channel(); - simple_file_logger::init_logger( - "git-function-history-gui", - simple_file_logger::LogLevel::Info, - ) - .expect("could not intialize logger"); - + simple_file_logger::init_logger!("git-function-history-gui") + .expect("could not intialize logger"); const ICON: &[u8] = include_bytes!("../resources/icon1.png"); let icon = image::load_from_memory_with_format(ICON, Png).expect("could not load image for icon"); diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 06e59633..f3fecb8a 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -682,7 +682,7 @@ mod tests { } #[test] - fn tet_date() { + fn test_date() { let now = Utc::now(); let output = get_function_history( "empty_test", @@ -702,7 +702,7 @@ mod tests { } #[test] - fn expensive_tes() { + fn expensive_test() { let now = Utc::now(); let output = get_function_history( "empty_test", From b2577f26a13a6a642a2c43c5d96ebba679b30d56 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Fri, 2 Dec 2022 13:54:32 -0500 Subject: [PATCH 143/172] removed some potentially panicking code, more to come --- git-function-history-gui/src/lib.rs | 14 +++-- git-function-history-lib/src/languages/go.rs | 14 ++--- git-function-history-lib/src/languages/mod.rs | 13 +++-- .../src/languages/ruby.rs | 4 +- .../src/languages/rust.rs | 19 ++++--- git-function-history-lib/src/lib.rs | 55 ++++++++++++------- git-function-history-lib/src/types.rs | 43 +++++++++------ 7 files changed, 96 insertions(+), 66 deletions(-) diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index 1a1aaac6..bfba6b4a 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -86,6 +86,7 @@ impl MyEguiApp { commit.get_metadata()["file"] ))); }); + let file = commit.get_file().map(|x| x.to_string()).unwrap_or_else(|| "error occured could not retrieve file please file a bug report to https://github.com/mendelsshop/git_function_history/issues".to_string()); match commit.get_move_direction() { Directions::None => { egui::CentralPanel::default().show(ctx, |ui| { @@ -94,7 +95,7 @@ impl MyEguiApp { .max_width(f32::INFINITY) .auto_shrink([false, false]) .show(ui, |ui| { - ui.add(Label::new(commit.get_file().to_string())); + ui.add(Label::new(file)); }); }); } @@ -115,7 +116,7 @@ impl MyEguiApp { .max_height(f32::INFINITY) .max_width(f32::INFINITY) .auto_shrink([false, false]) - .show(ui, |ui| ui.add(Label::new(commit.get_file().to_string()))); + .show(ui, |ui| ui.add(Label::new(file))); }); if resp.clicked() { commit.move_forward(); @@ -139,7 +140,7 @@ impl MyEguiApp { .max_width(f32::INFINITY) .auto_shrink([false, false]) .show(ui, |ui| { - ui.add(Label::new(commit.get_file().to_string())); + ui.add(Label::new(file)); }); }); if resp.clicked() { @@ -173,7 +174,7 @@ impl MyEguiApp { .max_width(f32::INFINITY) .auto_shrink([false, false]) .show(ui, |ui| { - ui.add(Label::new(commit.get_file().to_string())); + ui.add(Label::new(file)); }); }); if l_resp.clicked() { @@ -235,7 +236,10 @@ impl MyEguiApp { } }); }); - Self::draw_commit(history.get_mut_commit(), ctx, false); + // TODO: if no commit is found, show a message + if let Some(x) = history.get_mut_commit() { + Self::draw_commit(x, ctx, false) + } } } diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index 53872d20..5979362d 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -102,16 +102,10 @@ pub(crate) fn find_function_in_file( .to_string() .trim_end() .to_string(); - let index = super::turn_into_index(file_contents); - lines.1 = match super::get_from_index(&index, lines.1) { - Some(i) => i, - None => return None, - }; - lines.0 = match super::get_from_index(&index, lines.0) { - Some(i) => i, - None => return None, - }; - // lines.0 = start_line + 1; + let index = super::turn_into_index(file_contents).ok()?; + lines.1 = super::get_from_index(&index, lines.1)?; + lines.0 = super::get_from_index(&index, lines.0)?; + let start = lines.0; body = super::make_lined(&body, start); // see if the first parameter has a name: diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 4a7041f5..ad4b072c 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -1,4 +1,4 @@ -use crate::Filter; +use crate::{Filter, UnwrapToError}; use std::{ collections::HashMap, error::Error, @@ -169,7 +169,7 @@ pub trait FileTrait: fmt::Debug + fmt::Display { fn get_current(&self) -> Option>; } -fn turn_into_index(snippet: &str) -> HashMap> { +fn turn_into_index(snippet: &str) -> Result>, Box> { // turn snippet into a hashmap of line number to char index // so line 1 is 0 to 10, line 2 is 11 to 20, etc let mut index = HashMap::new(); @@ -181,11 +181,14 @@ fn turn_into_index(snippet: &str) -> HashMap> { line += 1; index.insert(line, vec![char_index]); } else { - index.get_mut(&line).unwrap().push(char_index); + index + .get_mut(&line) + .unwrap_to_error("line not found")? + .push(char_index); } char_index += c.len_utf8(); } - index + Ok(index) } fn get_from_index(index: &HashMap>, char: usize) -> Option { @@ -203,7 +206,7 @@ Python is cool Rust is cool Go is cool Ruby😂 is cool"; - let index = turn_into_index(snippet); + let index = turn_into_index(snippet).unwrap(); // assert_eq!(index[&0], vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); // assert_eq!(index[&0], vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); println!("done {index:?}"); diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 6c49803c..0aa0164b 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -68,7 +68,7 @@ pub(crate) fn find_function_in_file( let parsed = parser.do_parse(); let ast = parsed.ast.unwrap_to_error("Failed to parse file")?; let fns = get_functions_from_node(&ast, &None, name); - let index = super::turn_into_index(file_contents); + let index = super::turn_into_index(file_contents)?; fns.iter() .map(|(f, c)| { let class = match c { @@ -122,7 +122,7 @@ pub(crate) fn find_function_in_file( f.expression_l .with_begin(start) .source(&parsed.input) - .expect("Failed to get function body") + .unwrap_to_error("Failed to get source")? .trim_matches('\n'), starts, ), diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 5fec07de..4882ecd1 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -286,11 +286,12 @@ pub(crate) fn find_function_in_file( }; let generics = get_genrerics_and_lifetime(&function); let attr = get_doc_comments_and_attrs(&function); + let name = match function.name() { + Some(name) => name.to_string(), + None => return, + }; parent_fn.push(RustParentFunction { - name: function - .name() - .expect("could not retrieve function name") - .to_string(), + name, lifetime: generics.1, generics: generics.0, top: stuff.1 .0, @@ -322,10 +323,10 @@ pub(crate) fn find_function_in_file( let contents: String = file_contents[bb..f.syntax().text_range().end().into()].to_string(); let body = super::make_lined(&contents, start); let function = RustFunction { - name: f - .name() - .expect("could not retrieve function name") - .to_string(), + name: match f.name() { + Some(name) => name.to_string(), + None => continue, + }, body, block: parent_block, function: parent_fn, @@ -372,7 +373,7 @@ fn get_stuff( let end: usize = block.syntax().text_range().end().into(); // get the start and end lines let mut found_start_brace = 0; - let index = super::turn_into_index(file); + let index = super::turn_into_index(file).ok()?; let end_line = super::get_from_index(&index, end - 1)?; let start_line = super::get_from_index(&index, start.into())?; for (i, line) in file.chars().enumerate() { diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index f3fecb8a..cca229a7 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -172,9 +172,18 @@ pub fn get_function_history( Filter::Author(_) | Filter::AuthorEmail(_) | Filter::Message(_) - | Filter::DateRange(..) | Filter::None | Filter::CommitHash(_) => String::new(), + Filter::DateRange(start, end) => { + // check if start is before end + // vaildate that the dates are valid + let start = DateTime::parse_from_rfc2822(start)?.with_timezone(&Utc); + let end = DateTime::parse_from_rfc2822(end)?.with_timezone(&Utc); + if start > end { + Err("start date is after end date")?; + } + String::new() + } _ => Err("invalid filter")?, }; match file { @@ -217,10 +226,10 @@ pub fn get_function_history( let date = metadata.4; let start = DateTime::parse_from_rfc2822(start) .map(|i| i.with_timezone(&Utc)) - .expect("failed to parse start date"); + .expect("failed to parse start date, edge case shouldn't happen please file a bug to https://github.com/mendelsshop/git_function_history/issues"); let end = DateTime::parse_from_rfc2822(end) .map(|i| i.with_timezone(&Utc)) - .expect("failed to parse end date"); + .expect("failed to parse end date, edge case shouldn't happen please file a bug to https://github.com/mendelsshop/git_function_history/issues"); start <= date && date <= end } Filter::Author(author) => *author == metadata.2, @@ -247,14 +256,17 @@ pub fn get_function_history( if tree.is_empty() { None?; } - Some(Commit::new( - &i.1 .1, - tree, - &i.1 .4.to_rfc2822(), - &i.1 .2, - &i.1 .3, - &i.1 .0, - )) + Some( + Commit::new( + &i.1 .1, + tree, + &i.1 .4.to_rfc2822(), + &i.1 .2, + &i.1 .3, + &i.1 .0, + ) + .ok()?, + ) } Err(_) => None, } @@ -715,10 +727,15 @@ mod tests { match &output { Ok(functions) => { println!("{functions}"); - functions.get_commit().files.iter().for_each(|file| { - println!("file: {}", file.get_file_name()); - println!("{file}"); - }); + functions + .get_commit() + .unwrap() + .files + .iter() + .for_each(|file| { + println!("file: {}", file.get_file_name()); + println!("{file}"); + }); } Err(e) => println!("{e}"), } @@ -744,8 +761,8 @@ mod tests { } assert!(output.is_ok()); let output = output.unwrap(); - let commit = output.get_commit(); - let file = commit.get_file(); + let commit = output.get_commit().unwrap(); + let file = commit.get_file().unwrap(); let _functions = file.get_functions(); } @@ -768,8 +785,8 @@ mod tests { } assert!(output.is_ok()); let output = output.unwrap(); - let commit = output.get_commit(); - let file = commit.get_file(); + let commit = output.get_commit().unwrap(); + let file = commit.get_file().unwrap(); let _functions = file.get_functions(); } diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index 7dc41e52..b5e98c4c 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -128,17 +128,17 @@ impl Commit { author: &str, email: &str, message: &str, - ) -> Self { - Self { + ) -> Result> { + Ok(Self { commit_hash: commit_hash.to_string(), files, - date: DateTime::parse_from_rfc2822(date).expect("Failed to parse date"), + date: DateTime::parse_from_rfc2822(date)?, current_pos: 0, current_iter_pos: 0, author: author.to_string(), email: email.to_string(), message: message.to_string(), - } + }) } /// sets the current file to the next file if possible @@ -165,19 +165,19 @@ impl Commit { map.insert("date".to_string(), self.date.to_rfc2822()); map.insert( "file".to_string(), - self.files[self.current_pos].get_file_name(), + self.files.get(self.current_pos).map_or("error occured, could not get filename, no file found\nfile a bug to https://github.com/mendelsshop/git_function_history/issues".to_string(), FileTrait::get_file_name), ); map } /// returns the current file - pub fn get_file(&self) -> &FileType { - &self.files[self.current_pos] + pub fn get_file(&self) -> Option<&FileType> { + self.files.get(self.current_pos) } /// returns the current file (mutable) - pub fn get_file_mut(&mut self) -> &mut FileType { - &mut self.files[self.current_pos] + pub fn get_file_mut(&mut self) -> Option<&mut FileType> { + self.files.get_mut(self.current_pos) } /// tells you in which directions you can move through the files in the commit @@ -265,7 +265,14 @@ impl Iterator for Commit { impl Display for Commit { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - writeln!(f, "{}", self.files[self.current_pos])?; + writeln!( + f, + "{}", + match self.files.get(self.current_pos) { + Some(file) => file, + None => return Err(fmt::Error), + } + )?; Ok(()) } } @@ -320,12 +327,16 @@ impl FunctionHistory { /// this will move to the next file in the current commit if possible pub fn move_forward_file(&mut self) { - self.commit_history[self.current_pos].move_forward(); + self.commit_history + .get_mut(self.current_pos) + .map(Commit::move_forward); } /// this will move to the previous file in the current commit if possible pub fn move_back_file(&mut self) { - self.commit_history[self.current_pos].move_back(); + self.commit_history + .get_mut(self.current_pos) + .map(Commit::move_back); } /// this returns some metadata about the current commit @@ -335,13 +346,13 @@ impl FunctionHistory { } /// returns a mutable reference to the current commit - pub fn get_mut_commit(&mut self) -> &mut Commit { - &mut self.commit_history[self.current_pos] + pub fn get_mut_commit(&mut self) -> Option<&mut Commit> { + self.commit_history.get_mut(self.current_pos) } /// returns a reference to the current commit - pub fn get_commit(&self) -> &Commit { - &self.commit_history[self.current_pos] + pub fn get_commit(&self) -> Option<&Commit> { + self.commit_history.get(self.current_pos) } /// returns the directions in which ways you can move through the commit history From 6a324aabb0f1007307427633e8aa8b2f2b53f04a Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Sun, 11 Dec 2022 22:46:45 -0500 Subject: [PATCH 144/172] updated dependencies, clippied + fmted --- .github/dependabot.yml | 7 +++++ cargo-function-history/src/app/actions.rs | 27 ++++++++++--------- cargo-function-history/src/app/mod.rs | 10 +++---- cargo-function-history/src/app/ui.rs | 2 +- cargo-function-history/src/keys.rs | 12 ++++----- function_history_backend_thread/src/types.rs | 10 +++---- git-function-history-gui/Cargo.toml | 2 +- git-function-history-gui/src/lib.rs | 10 +++---- git-function-history-lib/Cargo.toml | 2 +- git-function-history-lib/src/languages/mod.rs | 4 +-- 10 files changed, 48 insertions(+), 38 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e8d486ab..78024aa5 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,3 +9,10 @@ updates: directory: "/" # Location of package manifests schedule: interval: "weekly" + + # Set update schedule for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every week + interval: "weekly" diff --git a/cargo-function-history/src/app/actions.rs b/cargo-function-history/src/app/actions.rs index 8cf8b2d4..2c64c96c 100644 --- a/cargo-function-history/src/app/actions.rs +++ b/cargo-function-history/src/app/actions.rs @@ -53,17 +53,20 @@ impl Action { /// Could display a user friendly short description of action impl Display for Action { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let str = match self { - Action::Quit => "Quit", - Action::TextEdit => "TextEdit", - Action::ScrollUp => "ScrollUp", - Action::ScrollDown => "ScrollDown", - Action::BackCommit => "BackCommit", - Action::ForwardCommit => "ForwardCommit", - Action::BackFile => "BackFile", - Action::ForwardFile => "ForwardFile", - }; - write!(f, "{}", str) + write!( + f, + "{}", + match self { + Action::Quit => "Quit", + Action::TextEdit => "TextEdit", + Action::ScrollUp => "ScrollUp", + Action::ScrollDown => "ScrollDown", + Action::BackCommit => "BackCommit", + Action::ForwardCommit => "ForwardCommit", + Action::BackFile => "BackFile", + Action::ForwardFile => "ForwardFile", + } + ) } } @@ -115,7 +118,7 @@ impl From> for Actions { .map(Action::to_string) .collect::>() .join(", "); - format!("Conflict key {} with actions {}", key, actions) + format!("Conflict key {key} with actions {actions}") }) .collect::>(); if !errors.is_empty() { diff --git a/cargo-function-history/src/app/mod.rs b/cargo-function-history/src/app/mod.rs index 17f0b829..bf29091c 100644 --- a/cargo-function-history/src/app/mod.rs +++ b/cargo-function-history/src/app/mod.rs @@ -252,8 +252,8 @@ impl App { } _ => { - log::debug!("invalid arg: {:?}", i); - self.status = Status::Error(format!("Invalid search {:?}", i)); + log::debug!("invalid arg: {i:?}"); + self.status = Status::Error(format!("Invalid search {i:?}")); return; } } @@ -315,14 +315,14 @@ impl App { let start = match start.parse::() { Ok(x) => x, Err(e) => { - self.status = Status::Error(format!("{}", e)); + self.status = Status::Error(format!("{e}")); return; } }; let end = match end.parse::() { Ok(x) => x, Err(e) => { - self.status = Status::Error(format!("{}", e)); + self.status = Status::Error(format!("{e}")); return; } }; @@ -383,7 +383,7 @@ impl App { } } other => { - self.status = Status::Error(format!("Invalid command: {}", other)); + self.status = Status::Error(format!("Invalid command: {other}")); } }, None => { diff --git a/cargo-function-history/src/app/ui.rs b/cargo-function-history/src/app/ui.rs index 25e740ab..fb29d195 100644 --- a/cargo-function-history/src/app/ui.rs +++ b/cargo-function-history/src/app/ui.rs @@ -118,7 +118,7 @@ fn draw_body(app: &mut App, mut pos: Rect, frame: &mut Frame) { a => a .to_string() .split('\n') - .map(|s| Spans::from(format!("{}\n", s))) + .map(|s| Spans::from(format!("{s}\n"))) .collect(), }; let body = Paragraph::new(tick_text) diff --git a/cargo-function-history/src/keys.rs b/cargo-function-history/src/keys.rs index 0c9eb226..08fe6740 100644 --- a/cargo-function-history/src/keys.rs +++ b/cargo-function-history/src/keys.rs @@ -99,7 +99,7 @@ impl Key { 10 => Key::F10, 11 => Key::F11, 12 => Key::F12, - _ => panic!("unknown function key: F{}", n), + _ => panic!("unknown function key: F{n}"), } } } @@ -110,11 +110,11 @@ impl Display for Key { Key::Alt(' ') => write!(f, "Alt+Space"), Key::Ctrl(' ') => write!(f, "Ctrl+Space"), Key::Char(' ') => write!(f, " "), - Key::Alt(c) => write!(f, "Alt+{}", c), - Key::Ctrl(c) => write!(f, "Ctrl+{}", c), - Key::Char(c) => write!(f, "{}", c), - Key::Shift(c) => write!(f, "Shift+{}", c), - _ => write!(f, "{:?}", self), + Key::Alt(c) => write!(f, "Alt+{c}"), + Key::Ctrl(c) => write!(f, "Ctrl+{c}"), + Key::Char(c) => write!(f, "{c}"), + Key::Shift(c) => write!(f, "Shift+{c}"), + _ => write!(f, "{self:?}"), } } } diff --git a/function_history_backend_thread/src/types.rs b/function_history_backend_thread/src/types.rs index 80a44453..75107a0c 100644 --- a/function_history_backend_thread/src/types.rs +++ b/function_history_backend_thread/src/types.rs @@ -73,11 +73,11 @@ impl fmt::Display for CommandResult { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { CommandResult::History(history) => { - write!(f, "{}", history) + write!(f, "{history}") } CommandResult::String(string) => { for line in string { - writeln!(f, "{}", line)?; + writeln!(f, "{line}")?; } Ok(()) } @@ -98,11 +98,11 @@ impl fmt::Display for Status { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Status::Ok(s) => match s { - Some(s) => write!(f, "Ok: {}", s), + Some(s) => write!(f, "Ok: {s}"), None => write!(f, "Ok"), }, - Status::Error(s) => write!(f, "Err {}", s), - Status::Warning(s) => write!(f, "Warn {}", s), + Status::Error(s) => write!(f, "Err {s}"), + Status::Warning(s) => write!(f, "Warn {s}"), Status::Loading => write!(f, "Loading..."), } } diff --git a/git-function-history-gui/Cargo.toml b/git-function-history-gui/Cargo.toml index dfb92b7c..ca47c0ba 100644 --- a/git-function-history-gui/Cargo.toml +++ b/git-function-history-gui/Cargo.toml @@ -17,7 +17,7 @@ parallel = ["git_function_history/parallel", "function_history_backend_thread/pa unstable = ["git_function_history/unstable", "function_history_backend_thread/unstable"] [dependencies] -eframe = {version = "0.19.0", features = ["dark-light"]} +eframe = {version = "0.20.1", features = ["dark-light"]} git_function_history = { path = "../git-function-history-lib", version = "0.6.2", default-features = false} function_history_backend_thread = { path = "../function_history_backend_thread", version = "0.2.2", default-features = false} simple_file_logger = "0.3.1" diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index bfba6b4a..6e106479 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -267,17 +267,17 @@ impl eframe::App for MyEguiApp { } Status::Ok(a) => match a { Some(a) => { - ui.colored_label(Color32::LIGHT_GREEN, format!("Ok: {}", a)); + ui.colored_label(Color32::LIGHT_GREEN, format!("Ok: {a}")); } None => { ui.colored_label(Color32::GREEN, "Ready"); } }, Status::Warning(a) => { - ui.colored_label(Color32::LIGHT_RED, format!("Warn: {}", a)); + ui.colored_label(Color32::LIGHT_RED, format!("Warn: {a}")); } Status::Error(a) => { - ui.colored_label(Color32::LIGHT_RED, format!("Error: {}", a)); + ui.colored_label(Color32::LIGHT_RED, format!("Error: {a}")); } } }); @@ -470,7 +470,7 @@ impl eframe::App for MyEguiApp { Ok(x) => x, Err(e) => { self.status = Status::Error( - format!("{}", e), + format!("{e}"), ); return; } @@ -479,7 +479,7 @@ impl eframe::App for MyEguiApp { Ok(x) => x, Err(e) => { self.status = Status::Error( - format!("{}", e), + format!("{e}"), ); return; } diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 2615924e..46127f71 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -18,7 +18,7 @@ cache = ["dep:cached"] [dependencies] chrono = "0.4.23" -ra_ap_syntax = "0.0.140" +ra_ap_syntax = "0.0.142" rayon = { version = "1.6.0", optional = true } # rustpython-parser = "0.1.2" # for end_lines but can't be publsihed b/c git depenency diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index ad4b072c..32a6d4a1 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -72,7 +72,7 @@ impl Language { #[cfg(feature = "unstable")] Self::All => "python, rust, go, or ruby", #[cfg(not(feature = "unstable"))] - Language::All => "python, rust, or ruby", + Self::All => "python, rust, or ruby", } } @@ -88,7 +88,7 @@ impl Language { #[cfg(feature = "unstable")] Self::All => &["py", "pyw", "rs", "go", "rb"], #[cfg(not(feature = "unstable"))] - Language::All => &["py", "pyw", "rs", "rb"], + Self::All => &["py", "pyw", "rs", "rb"], } } } From c615f05e6b102e3392be9d8c3ad58c03e58a9833 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Mon, 12 Dec 2022 23:49:24 -0500 Subject: [PATCH 145/172] removed some more potential panics from indexing --- cargo-function-history/src/app/mod.rs | 5 ++- cargo-function-history/src/app/ui.rs | 28 ++++++++++--- git-function-history-lib/src/languages/go.rs | 7 +++- git-function-history-lib/src/languages/mod.rs | 4 +- .../src/languages/rust.rs | 24 +++++++----- git-function-history-lib/src/types.rs | 39 +++++++++++++------ 6 files changed, 76 insertions(+), 31 deletions(-) diff --git a/cargo-function-history/src/app/mod.rs b/cargo-function-history/src/app/mod.rs index bf29091c..01f06806 100644 --- a/cargo-function-history/src/app/mod.rs +++ b/cargo-function-history/src/app/mod.rs @@ -338,7 +338,10 @@ impl App { filter = Filter::Directory(dir.to_string()); } _ => { - self.status = Status::Error(format!("Invalid filter {}", i[0])); + self.status = Status::Error(format!( + "Invalid filter {}", + i.first().unwrap_or(&"") + )); return; } } diff --git a/cargo-function-history/src/app/ui.rs b/cargo-function-history/src/app/ui.rs index fb29d195..aabba481 100644 --- a/cargo-function-history/src/app/ui.rs +++ b/cargo-function-history/src/app/ui.rs @@ -52,8 +52,17 @@ where ) .split(whole_chunks); app.get_result(); - draw_body(app, body_chunks[0], rect); - let width = body_chunks[0].width.max(3) - 3; // keep 2 for borders and 1 for cursor + draw_body( + app, + *body_chunks.get(0).expect("could not get area to draw"), + rect, + ); + let width = body_chunks + .get(0) + .expect("could not get area to draw") + .width + .max(3) + - 3; // keep 2 for borders and 1 for cursor let scroll = (app.input_buffer.cursor() as u16).max(width) - width; let input = Paragraph::new(app.input_buffer.value()) .style(match app.state() { @@ -67,18 +76,25 @@ where .style(Style::default().fg(Color::White)), ) .scroll((0, scroll)); - rect.render_widget(input, body_chunks[1]); + rect.render_widget( + input, + *body_chunks.get(1).expect("could not get area to draw"), + ); if let AppState::Editing = app.state() { // AppState::Editing => { rect.set_cursor( // Put cursor past the end of the input text - body_chunks[1].x + (app.input_buffer.cursor() as u16).min(width), + body_chunks.get(1).expect("could not get area to draw").x + + (app.input_buffer.cursor() as u16).min(width), // Move one line down, from the border to the input line - body_chunks[1].y, + body_chunks.get(1).expect("could not get area to draw").y, ) } let status = draw_status(app.status()); - rect.render_widget(status, body_chunks[2]); + rect.render_widget( + status, + *body_chunks.get(2).expect("could not get area to draw"), + ); } fn draw_body(app: &mut App, mut pos: Rect, frame: &mut Frame) { diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index 5979362d..ff5a1203 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -92,13 +92,16 @@ pub(crate) fn find_function_in_file( lines.0 = recv.pos(); } // TODO: make sure that func is not commented out - lines.0 = file_contents[..lines.0].rfind("func")?; + lines.0 = file_contents + .get(..lines.0) + .map_or(lines.0, |c| c.rfind("func").unwrap_or(lines.0)); for i in &func.docs { if i.pos < lines.0 { lines.0 = i.pos; } } - let mut body = file_contents[lines.0..=lines.1] + let mut body = file_contents + .get(lines.0..=lines.1)? .to_string() .trim_end() .to_string(); diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 32a6d4a1..1b045f3f 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -207,8 +207,8 @@ Rust is cool Go is cool Ruby😂 is cool"; let index = turn_into_index(snippet).unwrap(); - // assert_eq!(index[&0], vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - // assert_eq!(index[&0], vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + // assert_eq!(index.get(&0], vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); + // assert_eq!(index.get(&0], vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9)); println!("done {index:?}"); // assert_eq!(get_from_index(&index, 0), 0); diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 4882ecd1..72f66589 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -315,13 +315,19 @@ pub(crate) fn find_function_in_file( parent = p.parent(); } let attr = get_doc_comments_and_attrs(f); - let start = stuff.0 .0; - let bb = match map[&(start - 1)] { + let start_line = stuff.0 .0; + let start_idx = match map + .get(&(start_line - 1)) + .unwrap_to_error("could not get start index for function based off line number")? + { 0 => 0, - x => x + 1, + x => *x + 1, }; - let contents: String = file_contents[bb..f.syntax().text_range().end().into()].to_string(); - let body = super::make_lined(&contents, start); + let contents: String = file_contents + .get(start_idx..f.syntax().text_range().end().into()) + .unwrap_to_error("could not function text based off of start and stop indexes")? + .to_string(); + let body = super::make_lined(&contents, start_line); let function = RustFunction { name: match f.name() { Some(name) => name.to_string(), @@ -385,11 +391,11 @@ fn get_stuff( if found_start_brace == 0 { found_start_brace = usize::from(start); } - let start = map[&(start_line - 1)]; + let start_idx = map.get(&(start_line - 1))?; let start_lines = start_line; - let mut content: String = file[(*start)..=found_start_brace].to_string(); - if &content[..1] == "\n" { - content = content[1..].to_string(); + let mut content: String = file.get((**start_idx)..=found_start_brace)?.to_string(); + if content.get(..1)? == "\n" { + content = content.get(1..)?.to_string(); } Some(( (start_line, end_line), diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index b5e98c4c..e3e4fe7c 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -306,23 +306,29 @@ impl FunctionHistory { } /// this will move to the next commit if possible - pub fn move_forward(&mut self) { + pub fn move_forward(&mut self) -> Option<()> { if self.current_pos >= self.commit_history.len() - 1 { - return; + return None; } self.current_pos += 1; - self.commit_history[self.current_pos].current_iter_pos = 0; - self.commit_history[self.current_pos].current_pos = 0; + self.commit_history + .get_mut(self.current_pos)? + .current_iter_pos = 0; + self.commit_history.get_mut(self.current_pos)?.current_pos = 0; + Some(()) } /// this will move to the previous commit if possible - pub fn move_back(&mut self) { + pub fn move_back(&mut self) -> Option<()> { if self.current_pos == 0 { - return; + return None; } self.current_pos -= 1; - self.commit_history[self.current_pos].current_iter_pos = 0; - self.commit_history[self.current_pos].current_pos = 0; + self.commit_history + .get_mut(self.current_pos)? + .current_iter_pos = 0; + self.commit_history.get_mut(self.current_pos)?.current_pos = 0; + Some(()) } /// this will move to the next file in the current commit if possible @@ -342,7 +348,9 @@ impl FunctionHistory { /// this returns some metadata about the current commit /// including the `commit hash`, `date`, and `file` pub fn get_metadata(&self) -> HashMap { - self.commit_history[self.current_pos].get_metadata() + self.commit_history + .get(self.current_pos) + .map_or_else(HashMap::new, Commit::get_metadata) } /// returns a mutable reference to the current commit @@ -367,7 +375,9 @@ impl FunctionHistory { /// tells you in which directions you can move through the files in the current commit pub fn get_commit_move_direction(&self) -> Directions { - self.commit_history[self.current_pos].get_move_direction() + self.commit_history + .get(self.current_pos) + .map_or(Directions::None, Commit::get_move_direction) } /// returns a new `FunctionHistory` by filtering the current one by the filter specified (does not modify the current one). @@ -473,7 +483,14 @@ macro_rules! filter_by { impl Display for FunctionHistory { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - writeln!(f, "{}", self.commit_history[self.current_pos])?; + writeln!( + f, + "{}", + self.commit_history.get(self.current_pos).map_or( + "could not retrieve commit please file a bug".to_string(), + ToString::to_string + ) + )?; Ok(()) } } From e23d081085521892c46d06dbb1904c5871f33503 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Tue, 13 Dec 2022 14:39:13 -0500 Subject: [PATCH 146/172] msrv workflow --- .github/workflows/msrv.yml | 27 +++++++++++++++++++++++++++ git-function-history-lib/Cargo.toml | 3 ++- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/msrv.yml diff --git a/.github/workflows/msrv.yml b/.github/workflows/msrv.yml new file mode 100644 index 00000000..d7c65ae7 --- /dev/null +++ b/.github/workflows/msrv.yml @@ -0,0 +1,27 @@ +name: Examples + +on: + [pull_request, push] + +jobs: + create-msrv-badge: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: spenserblack/actions-msrv@master + id: get-msrv + with: + path: ./test/ + - name: Create Badge + run: curl https://img.shields.io/badge/minimum%20rust%20version-${{ steps.get-msrv.outputs.msrv }}-blue > msrv.svg + - name: Commit Badge + # If there are no changes to the badge this would error out. But it + # isn't a problem if there were no changes, so errors are allowed. + continue-on-error: true + run: | + git add msrv.svg + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git commit -m "Update MSRV badge [Skip CI]" + git push \ No newline at end of file diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 46127f71..0ad94973 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -7,6 +7,7 @@ repository = "https://github.com/mendelsshop/git_function_history/tree/main/git- keywords = ["git_function_history", "git", "function", ] categories = ["tools", "git"] description = "show function history from git" +rust-version = "1.62" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] default = ["parallel", "cache"] @@ -18,7 +19,7 @@ cache = ["dep:cached"] [dependencies] chrono = "0.4.23" -ra_ap_syntax = "0.0.142" +ra_ap_syntax = "0.0.143" rayon = { version = "1.6.0", optional = true } # rustpython-parser = "0.1.2" # for end_lines but can't be publsihed b/c git depenency From 021667e17100ba1a9f6b59d854f16d69c14266d9 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Tue, 13 Dec 2022 14:39:22 -0500 Subject: [PATCH 147/172] part of it --- .github/workflows/msrv.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/msrv.yml b/.github/workflows/msrv.yml index d7c65ae7..516e9c60 100644 --- a/.github/workflows/msrv.yml +++ b/.github/workflows/msrv.yml @@ -1,7 +1,9 @@ name: Examples on: - [pull_request, push] + pull_request: + push: + workflow_dispatch: jobs: create-msrv-badge: From e0df50b1258bc955aac59b7f4c593f2635bb2fa4 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Tue, 13 Dec 2022 14:42:32 -0500 Subject: [PATCH 148/172] needs version --- .github/workflows/msrv.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/msrv.yml b/.github/workflows/msrv.yml index 516e9c60..d31e2a50 100644 --- a/.github/workflows/msrv.yml +++ b/.github/workflows/msrv.yml @@ -11,7 +11,7 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: spenserblack/actions-msrv@master + - uses: spenserblack/actions-msrv@v0.4.1 id: get-msrv with: path: ./test/ From 734f947a176f7af59a1927d885bd0ad23063b4c7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 13 Dec 2022 19:43:22 +0000 Subject: [PATCH 149/172] Update MSRV badge [Skip CI] --- msrv.svg | 1 + 1 file changed, 1 insertion(+) create mode 100644 msrv.svg diff --git a/msrv.svg b/msrv.svg new file mode 100644 index 00000000..ff3b21fd --- /dev/null +++ b/msrv.svg @@ -0,0 +1 @@ +minimum rust version: minimum rust version \ No newline at end of file From 30ab7b13c2970714b9aae2dd827e2bfe459faab3 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Tue, 13 Dec 2022 14:46:17 -0500 Subject: [PATCH 150/172] testing 123..... --- .github/workflows/msrv.yml | 6 ++---- msrv.svg => resources/msrv.svg | 0 2 files changed, 2 insertions(+), 4 deletions(-) rename msrv.svg => resources/msrv.svg (100%) diff --git a/.github/workflows/msrv.yml b/.github/workflows/msrv.yml index d31e2a50..382e1439 100644 --- a/.github/workflows/msrv.yml +++ b/.github/workflows/msrv.yml @@ -1,4 +1,4 @@ -name: Examples +name: msrv-badge on: pull_request: @@ -13,10 +13,8 @@ jobs: - uses: actions/checkout@v2 - uses: spenserblack/actions-msrv@v0.4.1 id: get-msrv - with: - path: ./test/ - name: Create Badge - run: curl https://img.shields.io/badge/minimum%20rust%20version-${{ steps.get-msrv.outputs.msrv }}-blue > msrv.svg + run: curl https://img.shields.io/badge/minimum%20rust%20version-${{ steps.get-msrv.outputs.msrv }}-blue > resources/msrv.svg - name: Commit Badge # If there are no changes to the badge this would error out. But it # isn't a problem if there were no changes, so errors are allowed. diff --git a/msrv.svg b/resources/msrv.svg similarity index 100% rename from msrv.svg rename to resources/msrv.svg From d90a4a0ac7e76b07f14a595a1eca63c51c2bcd42 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Tue, 13 Dec 2022 15:00:15 -0500 Subject: [PATCH 151/172] wrong path in actioon --- .github/workflows/msrv.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/msrv.yml b/.github/workflows/msrv.yml index 382e1439..b4ce727f 100644 --- a/.github/workflows/msrv.yml +++ b/.github/workflows/msrv.yml @@ -20,7 +20,7 @@ jobs: # isn't a problem if there were no changes, so errors are allowed. continue-on-error: true run: | - git add msrv.svg + git add resources/msrv.svg git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git commit -m "Update MSRV badge [Skip CI]" From b78a45e1b2d6eebf7d909e9a7dd080b2429b3888 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 13 Dec 2022 20:12:41 +0000 Subject: [PATCH 152/172] Update MSRV badge [Skip CI] --- resources/msrv.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/msrv.svg b/resources/msrv.svg index ff3b21fd..01d90797 100644 --- a/resources/msrv.svg +++ b/resources/msrv.svg @@ -1 +1 @@ -minimum rust version: minimum rust version \ No newline at end of file +minimum rust version: 1.65.0minimum rust version1.65.0 \ No newline at end of file From 80e572e2a926a5436d55aa0c4b7fac82c6690660 Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Tue, 13 Dec 2022 15:37:38 -0500 Subject: [PATCH 153/172] added msrv badges, should update cargo.tom too --- .github/workflows/msrv.yml | 2 ++ README.md | 2 +- cargo-function-history/README.md | 2 +- function_history_backend_thread/README.md | 5 ++++- git-function-history-gui/README.md | 2 +- git-function-history-lib/README.md | 2 +- 6 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/msrv.yml b/.github/workflows/msrv.yml index b4ce727f..6a6d72aa 100644 --- a/.github/workflows/msrv.yml +++ b/.github/workflows/msrv.yml @@ -13,6 +13,8 @@ jobs: - uses: actions/checkout@v2 - uses: spenserblack/actions-msrv@v0.4.1 id: get-msrv + with: + set: true - name: Create Badge run: curl https://img.shields.io/badge/minimum%20rust%20version-${{ steps.get-msrv.outputs.msrv }}-blue > resources/msrv.svg - name: Commit Badge diff --git a/README.md b/README.md index 8791227a..d6863e61 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ![Custom badge](https://img.shields.io/endpoint?color=green&url=https%3A%2F%2Fraw.githubusercontent.com%2Fmendelsshop%2Fgit_function_history%2Fstats%2Floc.json) ![Custom badge](https://img.shields.io/endpoint?color=green&url=https%3A%2F%2Fraw.githubusercontent.com%2Fmendelsshop%2Fgit_function_history%2Fstats%2Fdownloads.json) [![dependency status](https://deps.rs/repo/github/mendelsshop/git_function_history/status.svg)](https://deps.rs/repo/github/mendelsshop/git_function_history) +# ![Custom badge](https://img.shields.io/endpoint?color=green&url=https%3A%2F%2Fraw.githubusercontent.com%2Fmendelsshop%2Fgit_function_history%2Fstats%2Floc.json) ![Custom badge](https://img.shields.io/endpoint?color=green&url=https%3A%2F%2Fraw.githubusercontent.com%2Fmendelsshop%2Fgit_function_history%2Fstats%2Fdownloads.json) [![dependency status](https://deps.rs/repo/github/mendelsshop/git_function_history/status.svg)](https://deps.rs/repo/github/mendelsshop/git_function_history) ![msrv](./resources/msrv.svg) # git function history diff --git a/cargo-function-history/README.md b/cargo-function-history/README.md index a0911ed1..3764aaf3 100644 --- a/cargo-function-history/README.md +++ b/cargo-function-history/README.md @@ -1,4 +1,4 @@ -# [![crates.io](https://img.shields.io/crates/v/cargo-function-history.svg?label=latest%20version)](https://crates.io/crates/cargo-function-history) [![Crates.io](https://img.shields.io/crates/d/cargo-function-history?label=crates.io%20downloads)](https://crates.io/crates/cargo-function-history) +# [![crates.io](https://img.shields.io/crates/v/cargo-function-history.svg?label=latest%20version)](https://crates.io/crates/cargo-function-history) [![Crates.io](https://img.shields.io/crates/d/cargo-function-history?label=crates.io%20downloads)](https://crates.io/crates/cargo-function-history) ![msrv](../resources/msrv.svg) # cargo function history diff --git a/function_history_backend_thread/README.md b/function_history_backend_thread/README.md index 67b52f06..7a59c665 100644 --- a/function_history_backend_thread/README.md +++ b/function_history_backend_thread/README.md @@ -1,3 +1,6 @@ +# [![crates.io](https://img.shields.io/crates/v/function_history_backend_thread.svg?label=latest%20version)](https://crates.io/crates/function_history_backend_thread) [![Crates.io](https://img.shields.io/crates/d/function_history_backend_thread?label=crates.io%20downloads)](function_history_backend_thread) ![msrv](../resources/msrv.svg) + + # Function History Backend Thread -Provides threading and custom types for [git-function-history-gui](https://github.com/mendelsshop/git_function_history/tree/main/git-function-history-gui) and [cargo-function-history](https://github.com/mendelsshop/git_function_history/tree/main/cargo-function-history) \ No newline at end of file +Provides threading and custom types for [git-function-history-gui](https://github.com/mendelsshop/git_function_history/tree/main/git-function-history-gui) and [cargo-function-history](https://github.com/mendelsshop/git_function_history/tree/main/cargo-function-history). diff --git a/git-function-history-gui/README.md b/git-function-history-gui/README.md index 4bb6ca80..c3fc3afa 100644 --- a/git-function-history-gui/README.md +++ b/git-function-history-gui/README.md @@ -1,4 +1,4 @@ -# [![crates.io](https://img.shields.io/crates/v/git-function-history-gui.svg?label=latest%20version)](https://crates.io/crates/git-function-history-gui) [![Crates.io](https://img.shields.io/crates/d/git-function-history-gui?label=crates.io%20downloads)](https://crates.io/crates/git-function-history-gui) +# [![crates.io](https://img.shields.io/crates/v/git-function-history-gui.svg?label=latest%20version)](https://crates.io/crates/git-function-history-gui) [![Crates.io](https://img.shields.io/crates/d/git-function-history-gui?label=crates.io%20downloads)](https://crates.io/crates/git-function-history-gui) ![msrv](../resources/msrv.svg) # git function history GUI diff --git a/git-function-history-lib/README.md b/git-function-history-lib/README.md index 929845d8..be94d87c 100644 --- a/git-function-history-lib/README.md +++ b/git-function-history-lib/README.md @@ -1,5 +1,5 @@ -# [![Clippy check + test](https://github.com/mendelsshop/git_function_history/actions/workflows/cargo_clippy_lib.yml/badge.svg)](https://github.com/mendelsshop/git_function_history/actions/workflows/cargo_clippy_lib.yml) [![crates.io](https://img.shields.io/crates/v/git_function_history.svg?label=latest%20version)](https://crates.io/crates/git_function_history) [![Crates.io](https://img.shields.io/crates/d/git_function_history?label=crates.io%20downloads)](https://crates.io/crates/git_function_history) [![docs.rs](https://img.shields.io/docsrs/git_function_history?logo=Docs.rs)](https://docs.rs/git_function_history/latest/git_function_history) +# [![Clippy check + test](https://github.com/mendelsshop/git_function_history/actions/workflows/cargo_clippy_lib.yml/badge.svg)](https://github.com/mendelsshop/git_function_history/actions/workflows/cargo_clippy_lib.yml) [![crates.io](https://img.shields.io/crates/v/git_function_history.svg?label=latest%20version)](https://crates.io/crates/git_function_history) [![Crates.io](https://img.shields.io/crates/d/git_function_history?label=crates.io%20downloads)](https://crates.io/crates/git_function_history) [![docs.rs](https://img.shields.io/docsrs/git_function_history?logo=Docs.rs)](https://docs.rs/git_function_history/latest/git_function_history) ![msrv](../resources/msrv.svg) # git function history From 1b1ef3577b23afeeca690ca03c52b18d2dc0e43e Mon Sep 17 00:00:00 2001 From: Mendel Rubin <82669516+mendelsshop@users.noreply.github.com> Date: Tue, 13 Dec 2022 16:21:56 -0500 Subject: [PATCH 154/172] update msrv in cargo.toml --- .github/workflows/msrv.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/msrv.yml b/.github/workflows/msrv.yml index 6a6d72aa..08ebd1dc 100644 --- a/.github/workflows/msrv.yml +++ b/.github/workflows/msrv.yml @@ -23,6 +23,7 @@ jobs: continue-on-error: true run: | git add resources/msrv.svg + git add **/Cargo.toml git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git commit -m "Update MSRV badge [Skip CI]" From 253b54aea4634fd38a036c74203090aa916f8b32 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 13 Dec 2022 16:39:15 -0500 Subject: [PATCH 155/172] plz work --- resources/msrv.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/msrv.svg b/resources/msrv.svg index 01d90797..857ae6cd 100644 --- a/resources/msrv.svg +++ b/resources/msrv.svg @@ -1 +1 @@ -minimum rust version: 1.65.0minimum rust version1.65.0 \ No newline at end of file +minimum rust version: 1.64.0minimum rust version1.65.0 \ No newline at end of file From 9867644127fb7318e39197d4e51ed56014fe5801 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 13 Dec 2022 21:48:24 +0000 Subject: [PATCH 156/172] Update MSRV badge [Skip CI] --- resources/msrv.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/msrv.svg b/resources/msrv.svg index 857ae6cd..01d90797 100644 --- a/resources/msrv.svg +++ b/resources/msrv.svg @@ -1 +1 @@ -minimum rust version: 1.64.0minimum rust version1.65.0 \ No newline at end of file +minimum rust version: 1.65.0minimum rust version1.65.0 \ No newline at end of file From 10e4e783c6c2bf7e18787bca6da5ce1cc8384304 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 13 Dec 2022 19:19:43 -0500 Subject: [PATCH 157/172] removed some allows for lints --- git-function-history-lib/Cargo.toml | 2 +- git-function-history-lib/src/languages/mod.rs | 10 +++ .../src/languages/python.rs | 4 +- git-function-history-lib/src/lib.rs | 68 ++++++++++++------- git-function-history-lib/src/types.rs | 12 ++++ 5 files changed, 68 insertions(+), 28 deletions(-) diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 0ad94973..7ddd1d00 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/mendelsshop/git_function_history/tree/main/git- keywords = ["git_function_history", "git", "function", ] categories = ["tools", "git"] description = "show function history from git" -rust-version = "1.62" + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] default = ["parallel", "cache"] diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 1b045f3f..6d2bed0c 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -46,6 +46,11 @@ pub enum LanguageFilter { } impl Language { + /// takes string and returns the corresponding language + /// + /// # Errors + /// + /// `Err` will be returned if the string is not a valid language pub fn from_string(s: &str) -> Result> { match s { "python" => Ok(Self::Python), @@ -163,6 +168,11 @@ fn make_lined(snippet: &str, mut start: usize) -> String { pub trait FileTrait: fmt::Debug + fmt::Display { fn get_file_name(&self) -> String; fn get_functions(&self) -> Vec>; + + /// # Errors + /// + /// returns `Err` if the wrong filter is given, only `PLFilter` and `FunctionInLines` variants of `Filter` are valid. + /// with `PLFilter` it will return `Err` if you mismatch the file type with the filter Ie: using `RustFile` and `PythonFilter` will return `Err`. fn filter_by(&self, filter: &Filter) -> Result> where Self: Sized; diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 787272a2..bb3828de 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -130,11 +130,11 @@ pub(crate) fn find_function_in_file( .. } = func.0.node { - let start_s = func.0.location.row(); + let start_line = func.0.location.row(); let mut body = file_contents[*starts..*ends] .trim_start_matches('\n') .to_string(); - body = super::make_lined(&body, start_s); + body = super::make_lined(&body, start_line); let class = func .1 .iter() diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index cca229a7..61b17970 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -1,16 +1,12 @@ #![warn(clippy::pedantic, clippy::nursery, clippy::cargo)] #![deny(clippy::use_self, rust_2018_idioms)] #![allow( - clippy::missing_panics_doc, clippy::must_use_candidate, - clippy::case_sensitive_file_extension_comparisons, - clippy::match_wildcard_for_single_variants, clippy::cast_possible_truncation, clippy::cast_sign_loss, clippy::cognitive_complexity, clippy::float_cmp, - clippy::similar_names, - clippy::missing_errors_doc, + // clippy::similar_names, clippy::return_self_not_must_use, clippy::module_name_repetitions, clippy::multiple_crate_versions, @@ -131,6 +127,12 @@ pub enum Filter { /// use git_function_history::{get_function_history, Filter, FileFilterType, Language}; /// let t = get_function_history("empty_test", &FileFilterType::Absolute("src/test_functions.rs".to_string()), &Filter::None, &Language::Rust).unwrap(); /// ``` +/// +/// # Errors +/// +/// If no files were found that match the criteria given, this will return an 'Err' +/// Or if it cannot find or read from a git repository +/// // TODO: split this function into smaller functions pub fn get_function_history( name: &str, @@ -189,7 +191,10 @@ pub fn get_function_history( match file { FileFilterType::Absolute(file) | FileFilterType::Relative(file) => { // vaildate that the file makes sense with language - let is_supported = langs.get_file_endings().iter().any(|i| file.ends_with(i)); + let is_supported = langs + .get_file_endings() + .iter() + .any(|i| ends_with_cmp_no_case(file, i)); if !is_supported { Err(format!("file {file} is not a {} file", langs.get_names()))?; } @@ -350,50 +355,51 @@ fn traverse_tree( FileFilterType::None => match langs { // #[cfg(feature = "c_lang")] // Language::C => { - // if file.ends_with(".c") || file.ends_with(".h") { + // if ends_with_cmp_no_case(&file, "c") || ends_with_cmp_no_case(&file, "h") { // files.push(file); // } // } #[cfg(feature = "unstable")] Language::Go => { - if !file.ends_with(".go") { + if !ends_with_cmp_no_case(&file, "go") { continue; } } Language::Python => { - if !file.ends_with(".py") { + if !ends_with_cmp_no_case(&file, "py") { continue; } } Language::Rust => { - if !file.ends_with(".rs") { + if !ends_with_cmp_no_case(&file, "rs") { continue; } } Language::Ruby => { - if !file.ends_with(".rb") { + if !ends_with_cmp_no_case(&file, "rb") { continue; } } Language::All => { cfg_if::cfg_if! { - if #[cfg(feature = "c_lang")] { - if !(file.ends_with(".c") || file.ends_with(".h") || !file.ends_with(".rs") || file.ends_with(".py") || file.ends_with(".rb")) { - continue; - } - } - else if #[cfg(feature = "unstable")] { - if !(file.ends_with(".go") || file.ends_with(".rs") || file.ends_with(".py") || file.ends_with(".rb")){ + // if #[cfg(feature = "c_lang")] { + // if !(ends_with_cmp_no_case(&file, "c") || ends_with_cmp_no_case(&file, "h") || !ends_with_cmp_no_case(&file, "rs") || ends_with_cmp_no_case(&file, "py") || ends_with_cmp_no_case(&file, "rb")) { + // continue; + // } + // } + // else + if #[cfg(feature = "unstable")] { + if !(ends_with_cmp_no_case(&file, "go") || ends_with_cmp_no_case(&file, "rs") || ends_with_cmp_no_case(&file, "py") || ends_with_cmp_no_case(&file, "rb")){ continue } } - else if #[cfg(all(feature = "unstable", feature = "c_lang"))] { - if !(file.ends_with(".go") || file.ends_with(".c") || file.ends_with(".h") || file.ends_with(".rs") || file.ends_with(".py") || file.ends_with(".rb")) { - continue; - } - } + // else if #[cfg(all(feature = "unstable", feature = "c_lang"))] { + // if !(ends_with_cmp_no_case(&file, "go") || ends_with_cmp_no_case(&file, "c") || ends_with_cmp_no_case(&file, "h") || ends_with_cmp_no_case(&file, "rs") || ends_with_cmp_no_case(&file, "py") || ends_with_cmp_no_case(&file, "rb")) { + // continue; + // } + // } else { - if !(file.ends_with(".rs") || file.ends_with(".py") || file.ends_with(".rb")) { + if !(ends_with_cmp_no_case(&file, "rs") || ends_with_cmp_no_case(&file, "py") || ends_with_cmp_no_case(&file, "rb")) { continue; } } @@ -463,6 +469,11 @@ macro_rules! get_function_history { }}; } +/// Returns a vec of information such as author, date, email, and message for each commit +/// +/// # Errors +/// wiil return `Err`if it cannot find or read from a git repository + pub fn get_git_info() -> Result, Box> { let repo = git_repository::discover(".")?; let mut tips = vec![]; @@ -583,6 +594,13 @@ fn find_function_in_files_with_commit( .collect() } +fn ends_with_cmp_no_case(filename: &str, file_ext: &str) -> bool { + let filename = std::path::Path::new(filename); + filename + .extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case(file_ext)) +} + trait UnwrapToError { fn unwrap_to_error_sync(self, message: &str) -> Result>; fn unwrap_to_error(self, message: &str) -> Result>; @@ -796,7 +814,7 @@ mod tests { // let now = Utc::now(); // let output = get_function_history( // "empty_test", - // &FileFilterType::Relative("src/test_functions.c".to_string()), + // &FileFilterType::Relative("src/test_functionsc".to_string()), // &Filter::DateRange( // "03 Oct 2022 11:27:23 -0400".to_owned(), // "05 Oct 2022 23:45:52 +0000".to_owned(), diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index e3e4fe7c..d0b0d969 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -121,6 +121,10 @@ pub struct Commit { impl Commit { /// Create a new `Commit` with the given `commit_hash`, functions, and date. + /// + /// # Errors + /// + /// will return `Err` if it cannot parse the date provided. pub fn new( commit_hash: &str, files: Vec, @@ -193,6 +197,10 @@ impl Commit { /// returns a new `Commit` by filtering the current one by the filter specified (does not modify the current one). /// /// valid filters are: `Filter::FunctionInLines`, and `Filter::FileAbsolute`, `Filter::FileRelative`, and `Filter::Directory`. + /// + /// # Errors + /// + /// Will result in an `Err` if a non-valid filter is give, or if no results are found for the given filter pub fn filter_by(&self, filter: &Filter) -> Result> { match filter { Filter::FileAbsolute(_) @@ -391,6 +399,10 @@ impl FunctionHistory { /// /// history.filter_by(&Filter::Directory("app".to_string())).unwrap(); /// ``` + /// + /// # Errors + /// + /// returns `Err` if no files or commits are match the filter specified pub fn filter_by(&self, filter: &Filter) -> Result> { #[cfg(feature = "parallel")] let t = self.commit_history.par_iter(); From cae32feefb64abbb0aac4152a35090fc866eed74 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 14 Dec 2022 20:20:49 -0500 Subject: [PATCH 158/172] lib: python files can now show decorators removed some more potentially panickking code addded a drop more documenation --- TODO.md | 6 +- git-function-history-gui/src/lib.rs | 14 ++- git-function-history-lib/src/languages/go.rs | 2 +- .../src/languages/python.rs | 87 ++++++++++++++----- .../src/languages/ruby.rs | 7 +- .../src/languages/rust.rs | 8 +- git-function-history-lib/src/lib.rs | 2 +- .../src/test_functions.py | 4 + .../src/test_functions.rs | 4 +- git-function-history-lib/src/types.rs | 17 +++- 10 files changed, 115 insertions(+), 36 deletions(-) diff --git a/TODO.md b/TODO.md index faf8ac3d..5598f73e 100644 --- a/TODO.md +++ b/TODO.md @@ -26,11 +26,11 @@ - [/] add support for other languages (currently only supports rust) - [x] save search queries and filters to a file - [ ] rework the way filters and filefilters are handled ie maybe use a builder pattern - - [ ] remove all potentially panicking code + - [/] remove all potentially panicking code - release 7.0: - python: - - [ ] save parent function and classes + - [x] save parent function and classes - [ ] save kwargs and varargs etc using the args enum and be able to filter by all args or just kwargs etc - ruby: - [ ] save kwargs and varargs etc using the args enum and be able to filter by all args or just kwargs etc @@ -43,3 +43,5 @@ - [ ] (possibly) use tree sitter to provide syntax highlighting - lib: - [x] possibly stop using Commmad::new("git") and use https://crates.io/crates/git_rs OR https://crates.io/crates/rs-git-lib OR https://crates.io/crates/gitoxide, to imporve performance with program compibilty assistant sevice on windows + + - [] move language module into its own crate diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index 6e106479..8cf1dd7d 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -208,8 +208,14 @@ impl MyEguiApp { Vec2::new(ui.available_width() - max, 2.0), Label::new(format!( "{}\n{}", - history.get_metadata()["commit hash"], - history.get_metadata()["date"] + history + .get_metadata() + .get("commit hash") + .map_or("could not retrieve commit hash", |x| x.as_str()), + history + .get_metadata() + .get("date") + .map_or("could not retieve date", |x| x.as_str()), )), ); @@ -239,6 +245,10 @@ impl MyEguiApp { // TODO: if no commit is found, show a message if let Some(x) = history.get_mut_commit() { Self::draw_commit(x, ctx, false) + } else { + TopBottomPanel::top("no_commit_found").show(ctx, |ui| { + ui.add(Label::new("no commit found")); + }); } } } diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index ff5a1203..972b3389 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -91,7 +91,7 @@ pub(crate) fn find_function_in_file( if let Some(recv) = func.recv { lines.0 = recv.pos(); } - // TODO: make sure that func is not commented out + // FIXME: make sure that func is not commented out lines.0 = file_contents .get(..lines.0) .map_or(lines.0, |c| c.rfind("func").unwrap_or(lines.0)); diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index bb3828de..7fde0544 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -15,7 +15,7 @@ pub struct PythonFunction { pub(crate) body: String, pub(crate) parameters: Params, pub(crate) parent: Vec, - pub(crate) decorators: Vec, + pub(crate) decorators: Vec<(usize, String)>, pub(crate) class: Vec, pub(crate) lines: (usize, usize), pub(crate) returns: Option, @@ -66,7 +66,7 @@ pub struct PythonClass { pub(crate) name: String, pub(crate) top: String, pub(crate) lines: (usize, usize), - pub(crate) decorators: Vec, + pub(crate) decorators: Vec<(usize, String)>, } #[derive(Debug, Clone)] pub struct PythonParentFunction { @@ -74,7 +74,7 @@ pub struct PythonParentFunction { pub(crate) top: String, pub(crate) lines: (usize, usize), pub(crate) parameters: Params, - pub(crate) decorators: Vec, + pub(crate) decorators: Vec<(usize, String)>, pub(crate) returns: Option, } @@ -113,8 +113,7 @@ pub(crate) fn find_function_in_file( .end_location .unwrap_to_error("no end location for this function")? .row(); - let starts = map[&(start - 1)]; - let ends = map[&(end - 1)]; + let (Some(starts), Some(ends)) = (map.get(&(start - 1)), map.get(&(end - 1))) else { continue }; if let StmtKind::FunctionDef { name, args, @@ -131,10 +130,12 @@ pub(crate) fn find_function_in_file( } = func.0.node { let start_line = func.0.location.row(); - let mut body = file_contents[*starts..*ends] - .trim_start_matches('\n') - .to_string(); - body = super::make_lined(&body, start_line); + let body = match file_contents.get(**starts..**ends) { + Some(str) => str, + None => continue, + } + .trim_start_matches('\n'); + let body = super::make_lined(body, start_line); let class = func .1 .iter() @@ -153,7 +154,7 @@ pub(crate) fn find_function_in_file( None => return None, }; let top = format!("{start}: {top}"); - let decorators = get_decorator_list(decorator_list); + let decorators = get_decorator_list_new(decorator_list, file_contents); return Some(PythonClass { name: name.to_string(), top, @@ -192,7 +193,7 @@ pub(crate) fn find_function_in_file( None => return None, }; let top = format!("{start}: {top}"); - let decorators = get_decorator_list(decorator_list); + let decorators = get_decorator_list_new(decorator_list, file_contents); let parameters = get_args(*args.clone()); let returns = get_return_type(returns.clone()); return Some(PythonParentFunction { @@ -213,7 +214,7 @@ pub(crate) fn find_function_in_file( name: name.to_string(), parameters: get_args(*args), parent, - decorators: get_decorator_list(&decorator_list), + decorators: get_decorator_list_new(&decorator_list, file_contents), returns: get_return_type(returns), class, body, @@ -445,13 +446,48 @@ fn get_return_type(retr: Option>>) -> Option { } None } +#[allow(dead_code)] +// keeping this here just in case +fn get_decorator_list(decorator_list: &[Located]) -> Vec<(usize, String)> { + decorator_list + .iter() + .map(located_expr_to_decorator) + .collect::>() +} + +fn located_expr_to_decorator(expr: &Located) -> (usize, String) { + ( + expr.location.row(), + format!( + "{}:{}decorator with {}", + expr.location.row(), + vec![" "; expr.location.column()].join(""), + expr.node.name() + ), + ) +} -fn get_decorator_list(decorator_list: &[Located]) -> Vec { - // todo add full test version ie not just name and also add line numbers so it can be displayed/retrieved with get_tops +fn get_located_expr_line(expr: &Located, file_contents: &str) -> Option { + // does not add line numbers to string + file_contents + .lines() + .nth(expr.location.row() - 1) + .map(ToString::to_string) +} + +fn get_decorator_list_new( + decorator_list: &[Located], + file_contents: &str, +) -> Vec<(usize, String)> { decorator_list .iter() - .map(|x| x.node.name().to_string()) - .collect::>() + .map(|x| { + get_located_expr_line(x, file_contents).map_or_else( + || located_expr_to_decorator(x), + |dec| (x.location.row(), super::make_lined(&dec, x.location.row())), + ) + }) + .collect::>() } #[derive(Debug, Clone, PartialEq, Eq)] @@ -488,15 +524,17 @@ impl PythonFilter { Self::HasParameterName(parameter_name) => { function.parameters.arg_has_name(parameter_name) } - Self::HasDecorator(decorator) => function.decorators.iter().any(|x| x == decorator), + Self::HasDecorator(decorator) => { + function.decorators.iter().any(|x| x.1.contains(decorator)) + } Self::HasClasswithDecorator(decorator) => function .class .iter() - .any(|x| x.decorators.iter().any(|y| y == decorator)), + .any(|x| x.decorators.iter().any(|y| y.1.contains(decorator))), Self::HasParentFunctionwithDecorator(decorator) => function .parent .iter() - .any(|x| x.decorators.iter().any(|x| x == decorator)), + .any(|x| x.decorators.iter().any(|x| x.1.contains(decorator))), Self::HasParentFunctionwithParameterName(parameter_name) => function .parent .iter() @@ -510,15 +548,24 @@ impl PythonFilter { } impl FunctionTrait for PythonFunction { - // TODO: return decorator list too fn get_tops(&self) -> Vec<(String, usize)> { let mut tops = Vec::new(); for class in &self.class { tops.push((class.top.clone(), class.lines.0)); + for decorator in &class.decorators { + tops.push((decorator.1.clone(), decorator.0)); + } + } + for decorator in &self.decorators { + tops.push((decorator.1.clone(), decorator.0)); } for parent in &self.parent { tops.push((parent.top.clone(), parent.lines.0)); + for decorator in &parent.decorators { + tops.push((decorator.1.clone(), decorator.0)); + } } + tops.sort_by(|top1, top2| top1.1.cmp(&top2.1)); tops } diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 0aa0164b..223c1537 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -80,7 +80,6 @@ pub(crate) fn find_function_in_file( let loc_end = c.end_l; let top = Loc { begin: c.expression_l.begin, - // TODO: check if there is a super class map_or to that end: c .body .as_ref() @@ -88,7 +87,7 @@ pub(crate) fn find_function_in_file( }; let mut top = top .source(&parsed.input) - .unwrap_to_error("Failed to get source")?; + .unwrap_to_error("Failed to get top of class from source")?; top = top.trim_end().to_string(); top = super::make_lined(&top, start_line); Some(RubyClass { @@ -99,7 +98,7 @@ pub(crate) fn find_function_in_file( bottom: super::make_lined( loc_end .source(&parsed.input) - .unwrap_to_error("Failed to get source")? + .unwrap_to_error("Failed to get last line of class source")? .trim_matches('\n'), end_line, ), @@ -122,7 +121,7 @@ pub(crate) fn find_function_in_file( f.expression_l .with_begin(start) .source(&parsed.input) - .unwrap_to_error("Failed to get source")? + .unwrap_to_error("Failed to get function body from source")? .trim_matches('\n'), starts, ), diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 72f66589..7e5e670e 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -24,6 +24,7 @@ pub struct RustFunction { /// The lifetime of the function pub(crate) lifetime: Vec, /// The generic types of the function + /// also includes lifetimes pub(crate) generics: Vec, /// The arguments of the function pub(crate) arguments: HashMap, @@ -82,6 +83,7 @@ pub struct RustParentFunction { /// The lifetime of the function pub(crate) lifetime: Vec, /// The generic types of the function + /// also includes lifetimes pub(crate) generics: Vec, /// The arguments of the function pub(crate) arguments: HashMap, @@ -136,6 +138,7 @@ pub struct Block { /// The lifetime of the function pub(crate) lifetime: Vec, /// The generic types of the function + /// also includes lifetimes pub(crate) generics: Vec, /// The blocks atrributes pub(crate) attributes: Vec, @@ -407,11 +410,14 @@ fn get_stuff( } #[inline] fn get_genrerics_and_lifetime(block: &T) -> (Vec, Vec) { - // TODO: map trait bounds from where clauses to the generics and also use type_or_const_params + // TODO: map trait bounds from where clauses to the generics so it will return a (HashMap>, HashMap>) + // the key of each hashmap will be the name of the generic/lifetime and the values will be the trait bounds + // and also use type_or_const_params block.generic_param_list().map_or_else( || (vec![], vec![]), |gt| { ( + // gt. gt.generic_params() .map(|gt| gt.to_string()) .collect::>(), diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 61b17970..3ff6cf20 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -387,7 +387,7 @@ fn traverse_tree( // continue; // } // } - // else + // else if #[cfg(feature = "unstable")] { if !(ends_with_cmp_no_case(&file, "go") || ends_with_cmp_no_case(&file, "rs") || ends_with_cmp_no_case(&file, "py") || ends_with_cmp_no_case(&file, "rb")){ continue diff --git a/git-function-history-lib/src/test_functions.py b/git-function-history-lib/src/test_functions.py index a14517a7..3142b433 100644 --- a/git-function-history-lib/src/test_functions.py +++ b/git-function-history-lib/src/test_functions.py @@ -15,6 +15,9 @@ def wrapper(*args, **kwargs): def test_with_assert(y, n,/,c=7, *, a , args, **kwargs): @assert_that("This is a test with an assert") + + + def empty_test(t): return t == n @@ -24,6 +27,7 @@ class Test: pass passing_test = test_with_assert @assert_that("This is a test with an assert") + def empty_test(n: int) -> list: """This is an empty test with a docstring""" pass diff --git a/git-function-history-lib/src/test_functions.rs b/git-function-history-lib/src/test_functions.rs index 6d235b49..dc8588d2 100644 --- a/git-function-history-lib/src/test_functions.rs +++ b/git-function-history-lib/src/test_functions.rs @@ -15,7 +15,7 @@ pub struct Test { pub history: Vec, } -implTest { +implTest { /// empty test pub fn empty_test<'a>() { println!("empty test"); @@ -127,7 +127,7 @@ super_trait + Clone, A: Debug + Clone { - pub fn empty_test<'a>() { + pub fn empty_test<'a>() where 'a: Debug { println!("empty test"); } diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index d0b0d969..be740c01 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -475,7 +475,18 @@ impl FunctionHistory { }) } } -// TODO: add docs + +/// Macro to filter a the whole git history, a singe commit, or a file. +/// +/// All variants take the thing to be filtered as the first argument. +/// +/// If you just want to pass in a filter of type `Filter` pass in as the second argument the filter. +/// +/// if you just want to pass in a `LanguageFilter` pass in as the second argument the filter and the final argument literal such as 5 or 'a' or "a". +/// This is just to differentiate between the first two variants of the macro. +/// +/// Finally, if you just want to pass in a specific `LanguageFilter` like `RustFilter` pass in as the second argument the filter +/// and the 3rd argument should the variant of `LanguageFilter` such as `Rust` #[macro_export] macro_rules! filter_by { // option 1: takes a filter @@ -487,9 +498,9 @@ macro_rules! filter_by { $self.filter_by(&Filter::PLFilter($pl_filter)) }; // option 3: takes a language specific filter ie RustFilter and a language ie Rust - ($self:expr, $rust_filter:expr, $language:ident) => {{ + ($self:expr, $lang_filter:expr, $language:ident) => {{ use $crate::languages::LanguageFilter; - $self.filter_by(&Filter::PLFilter(LanguageFilter::$language($rust_filter))) + $self.filter_by(&Filter::PLFilter(LanguageFilter::$language($lang_filter))) }}; } From de93e4423a3e72b02bff47cdad8f1987ec2786e9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 14 Dec 2022 20:25:33 -0500 Subject: [PATCH 159/172] ideas --- TODO.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TODO.md b/TODO.md index 5598f73e..9be10822 100644 --- a/TODO.md +++ b/TODO.md @@ -45,3 +45,5 @@ - [x] possibly stop using Commmad::new("git") and use https://crates.io/crates/git_rs OR https://crates.io/crates/rs-git-lib OR https://crates.io/crates/gitoxide, to imporve performance with program compibilty assistant sevice on windows - [] move language module into its own crate + - general: + - [ ] update readmes with feautes and benchamrks specifically the repo & git-function-history-lib readmes From d267b42c2c183c1241287c545a0ffbb05ca5eadc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 16 Dec 2022 00:02:21 -0500 Subject: [PATCH 160/172] ruby ideas --- TODO.md | 4 ++-- git-function-history-lib/src/languages/mod.rs | 17 ----------------- git-function-history-lib/src/languages/ruby.rs | 9 +++++++++ 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/TODO.md b/TODO.md index 9be10822..b13dd550 100644 --- a/TODO.md +++ b/TODO.md @@ -31,7 +31,7 @@ - release 7.0: - python: - [x] save parent function and classes - - [ ] save kwargs and varargs etc using the args enum and be able to filter by all args or just kwargs etc + - [x] save kwargs and varargs etc using the args enum and be able to filter by all args or just kwargs etc - ruby: - [ ] save kwargs and varargs etc using the args enum and be able to filter by all args or just kwargs etc - gui: @@ -44,6 +44,6 @@ - lib: - [x] possibly stop using Commmad::new("git") and use https://crates.io/crates/git_rs OR https://crates.io/crates/rs-git-lib OR https://crates.io/crates/gitoxide, to imporve performance with program compibilty assistant sevice on windows - - [] move language module into its own crate + - [ ] move language module into its own crate - general: - [ ] update readmes with feautes and benchamrks specifically the repo & git-function-history-lib readmes diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 6d2bed0c..0a43a047 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -209,23 +209,6 @@ fn get_from_index(index: &HashMap>, char: usize) -> Option { diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 223c1537..171f2835 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -166,14 +166,19 @@ fn get_functions_from_node( } fn parse_args_from_node(node: &lib_ruby_parser::Node) -> Vec { + // TODO: make a Args struct has fields {args: Vec, kwargs, kwoptargs, optargs, kwrestargs, block_args, kwnilarg: bool, fowardarg: bool} + // where I didnt annotate a type its needs to be figured out the args purpose and anoatate the type based on that match node { lib_ruby_parser::Node::Args(args) => args .args .iter() .map(|arg| match arg { + // basic arg lib_ruby_parser::Node::Arg(arg) => arg.name.clone(), + lib_ruby_parser::Node::Kwarg(arg) => arg.name.clone(), lib_ruby_parser::Node::Kwoptarg(arg) => arg.name.clone(), + // arg that has a default value lib_ruby_parser::Node::Optarg(arg) => arg.name.clone(), lib_ruby_parser::Node::Restarg(arg) => arg .name @@ -183,6 +188,10 @@ fn parse_args_from_node(node: &lib_ruby_parser::Node) -> Vec { .name .as_ref() .map_or_else(String::new, ToString::to_string), + lib_ruby_parser::Node::ForwardArg(arg) => String::new(), + lib_ruby_parser::Node::Blockarg(arg) => String::new(), + lib_ruby_parser::Node::Kwnilarg(arg) => String::new(), + // Node::ForwardedArgs and Node::Kwargs are for method calls and not definitions thus we are not matching on them _ => String::new(), }) .filter(|f| !f.is_empty()) From 1721d5013e311c2409733e0171d90e42a2662536 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 18 Dec 2022 23:03:34 -0500 Subject: [PATCH 161/172] ruby now uses its own custom param data type --- git-function-history-lib/Cargo.toml | 2 +- .../src/languages/python.rs | 17 ++- .../src/languages/ruby.rs | 122 +++++++++++++----- .../src/test_functions.py | 4 +- 4 files changed, 101 insertions(+), 44 deletions(-) diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 7ddd1d00..503f09c7 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -23,7 +23,7 @@ ra_ap_syntax = "0.0.143" rayon = { version = "1.6.0", optional = true } # rustpython-parser = "0.1.2" # for end_lines but can't be publsihed b/c git depenency -rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "f885db8c61514f069979861f6b3bd83292086231" } +rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" } lib-ruby-parser = "3.0.12" gosyn = {version = "0.2.0", optional = true} # can't be published b/c git dependency diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 7fde0544..7634b756 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -13,7 +13,7 @@ use super::FunctionTrait; pub struct PythonFunction { pub(crate) name: String, pub(crate) body: String, - pub(crate) parameters: Params, + pub(crate) parameters: PythonParams, pub(crate) parent: Vec, pub(crate) decorators: Vec<(usize, String)>, pub(crate) class: Vec, @@ -40,7 +40,7 @@ pub struct Param { } #[derive(Debug, Clone)] -pub struct Params { +pub struct PythonParams { pub args: Vec, pub kwargs: Vec, pub posonlyargs: Vec, @@ -48,7 +48,7 @@ pub struct Params { pub varkwargs: Option, } -impl Params { +impl PythonParams { pub fn arg_has_name(&self, name: &str) -> bool { self.args.iter().any(|arg| arg.name == name) || self.kwargs.iter().any(|arg| arg.name == name) @@ -73,7 +73,7 @@ pub struct PythonParentFunction { pub(crate) name: String, pub(crate) top: String, pub(crate) lines: (usize, usize), - pub(crate) parameters: Params, + pub(crate) parameters: PythonParams, pub(crate) decorators: Vec<(usize, String)>, pub(crate) returns: Option, } @@ -366,15 +366,17 @@ fn get_functions( _ => {} } } - -fn get_args(args: Arguments) -> Params { - let mut parameters = Params { +// TODO save arg.defaults & arg.kwdefaults and attempt to map them to the write parameters +fn get_args(args: Arguments) -> PythonParams { + let mut parameters = PythonParams { args: Vec::new(), varargs: None, posonlyargs: Vec::new(), kwargs: Vec::new(), varkwargs: None, }; + println!("arg defaultes {:?}", args.defaults); + println!("kwarg defaultes {:?}", args.kw_defaults); for arg in args.args { parameters.args.push(Param { name: arg.node.arg, @@ -435,6 +437,7 @@ fn get_args(args: Arguments) -> Params { }), }); } + parameters } diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 171f2835..6eb40250 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -14,16 +14,16 @@ pub struct RubyFunction { pub name: String, pub lines: (usize, usize), pub class: Option, - pub args: Vec, + pub args: RubyParams, pub body: String, } impl RubyFunction { - pub fn new( + pub const fn new( name: String, lines: (usize, usize), class: Option, - args: Vec, + args: RubyParams, body: String, ) -> Self { Self { @@ -60,6 +60,54 @@ pub struct RubyClass { pub bottom: String, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct RubyParams { + args: Vec, + kwargs: Vec, + kwnilarg: bool, + forwarded_args: bool, + /// arg name, default value + optargs: Vec<(String, String)>, + kwoptargs: Vec<(String, String)>, + kwrestarg: Option, + restarg: Option, +} + +impl RubyParams { + pub const fn new() -> Self { + Self { + args: Vec::new(), + kwnilarg: false, + forwarded_args: false, + optargs: Vec::new(), + kwrestarg: None, + restarg: None, + kwargs: Vec::new(), + kwoptargs: Vec::new(), + } + } + + fn contains(&self, name: &String) -> bool { + self.args.contains(name) + || self.kwargs.contains(name) + || self + .optargs + .iter() + .any(|(arg, default)| arg == name || default == name) + || self + .kwoptargs + .iter() + .any(|(arg, default)| arg == name || default == name) + || Some(name.clone()) == self.kwrestarg + || Some(name.clone()) == self.restarg + } +} +impl Default for RubyParams { + fn default() -> Self { + Self::new() + } +} + pub(crate) fn find_function_in_file( file_contents: &str, name: &str, @@ -128,7 +176,7 @@ pub(crate) fn find_function_in_file( args: f .args .clone() - .map_or_else(Vec::new, |a| parse_args_from_node(&a)), + .map_or_else(RubyParams::new, |a| parse_args_from_node(&a)), }) }) .collect() @@ -165,40 +213,46 @@ fn get_functions_from_node( } } -fn parse_args_from_node(node: &lib_ruby_parser::Node) -> Vec { +fn parse_args_from_node(node: &lib_ruby_parser::Node) -> RubyParams { // TODO: make a Args struct has fields {args: Vec, kwargs, kwoptargs, optargs, kwrestargs, block_args, kwnilarg: bool, fowardarg: bool} // where I didnt annotate a type its needs to be figured out the args purpose and anoatate the type based on that - match node { - lib_ruby_parser::Node::Args(args) => args - .args - .iter() - .map(|arg| match arg { - // basic arg - lib_ruby_parser::Node::Arg(arg) => arg.name.clone(), + let mut ret_args = RubyParams::new(); + if let lib_ruby_parser::Node::Args(args) = node { + args.args.iter().for_each(|arg| match arg { + // basic arg + //python/ruby + lib_ruby_parser::Node::Arg(arg) => ret_args.args.push(arg.name.clone()), + lib_ruby_parser::Node::Kwarg(arg) => ret_args.kwargs.push(arg.name.clone()), - lib_ruby_parser::Node::Kwarg(arg) => arg.name.clone(), - lib_ruby_parser::Node::Kwoptarg(arg) => arg.name.clone(), - // arg that has a default value - lib_ruby_parser::Node::Optarg(arg) => arg.name.clone(), - lib_ruby_parser::Node::Restarg(arg) => arg - .name - .as_ref() - .map_or_else(String::new, ToString::to_string), - lib_ruby_parser::Node::Kwrestarg(arg) => arg - .name - .as_ref() - .map_or_else(String::new, ToString::to_string), - lib_ruby_parser::Node::ForwardArg(arg) => String::new(), - lib_ruby_parser::Node::Blockarg(arg) => String::new(), - lib_ruby_parser::Node::Kwnilarg(arg) => String::new(), - // Node::ForwardedArgs and Node::Kwargs are for method calls and not definitions thus we are not matching on them - _ => String::new(), - }) - .filter(|f| !f.is_empty()) - .collect(), - _ => vec![], + // args that has a default value + // TODO: get the default value + lib_ruby_parser::Node::Kwoptarg(arg) => { + ret_args.kwoptargs.push((arg.name.clone(), String::new())); + } + lib_ruby_parser::Node::Optarg(arg) => { + ret_args.optargs.push((arg.name.clone(), String::new())); + } + + lib_ruby_parser::Node::Restarg(arg) => { + if let Some(name) = &arg.name { + ret_args.restarg = Some(name.clone()); + } + } + lib_ruby_parser::Node::Kwrestarg(arg) => { + if let Some(name) = &arg.name { + ret_args.kwrestarg = Some(name.clone()); + } + } + + // ruby specific + lib_ruby_parser::Node::ForwardArg(_) => ret_args.forwarded_args = true, + lib_ruby_parser::Node::Kwnilarg(_) => ret_args.kwnilarg = true, + // Node::ForwardedArgs and Node::Kwargs are for method calls and not definitions thus we are not matching on them + // Node::Blockarg is for block methods similar to labmdas whic we do not currently support + _ => {} + }); }; - vec![] + ret_args } fn parser_class_name(class: &Class) -> String { diff --git a/git-function-history-lib/src/test_functions.py b/git-function-history-lib/src/test_functions.py index 3142b433..4c0e87d4 100644 --- a/git-function-history-lib/src/test_functions.py +++ b/git-function-history-lib/src/test_functions.py @@ -13,7 +13,7 @@ def wrapper(*args, **kwargs): return wrapper return decorator -def test_with_assert(y, n,/,c=7, *, a , args, **kwargs): +def test_with_assert(y, n,/,c=7, *, a ,aas = ["a", "b"], **krer,): @assert_that("This is a test with an assert") @@ -36,7 +36,7 @@ class TestClass: def test_method(self): pass - def test_with_assert(n: Test): + def test_with_assert(n: Test, a =10,* argss, ** args): @assert_that("This is a test with an assert") def empty_test(t): return t == n From f204bf48a04040fb1f1188b35443753c27f13879 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 19 Dec 2022 16:18:58 -0500 Subject: [PATCH 162/172] ruby functions support multiple classes now --- .../src/languages/python.rs | 2 - .../src/languages/ruby.rs | 140 +++++++++--------- .../src/test_functions.rb | 19 ++- 3 files changed, 84 insertions(+), 77 deletions(-) diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 7634b756..cc4777d4 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -375,8 +375,6 @@ fn get_args(args: Arguments) -> PythonParams { kwargs: Vec::new(), varkwargs: None, }; - println!("arg defaultes {:?}", args.defaults); - println!("kwarg defaultes {:?}", args.kw_defaults); for arg in args.args { parameters.args.push(Param { name: arg.node.arg, diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 6eb40250..9713b2af 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -2,6 +2,7 @@ use std::{error::Error, fmt}; use lib_ruby_parser::{ nodes::{Class, Def}, + source::DecodedInput, Loc, Parser, ParserOptions, }; @@ -13,7 +14,7 @@ use super::FunctionTrait; pub struct RubyFunction { pub name: String, pub lines: (usize, usize), - pub class: Option, + pub class: Vec, pub args: RubyParams, pub body: String, } @@ -22,7 +23,7 @@ impl RubyFunction { pub const fn new( name: String, lines: (usize, usize), - class: Option, + class: Vec, args: RubyParams, body: String, ) -> Self { @@ -38,14 +39,12 @@ impl RubyFunction { impl fmt::Display for RubyFunction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self.class { - Some(class) => write!(f, "{}\n...\n", class.top)?, - None => {} + for class in &self.class { + write!(f, "{}", class.top)?; } write!(f, "{}", self.body)?; - match &self.class { - Some(class) => write!(f, "\n...\n{}", class.bottom)?, - None => {} + for class in &self.class { + write!(f, "{}", class.bottom)?; } Ok(()) } @@ -54,7 +53,7 @@ impl fmt::Display for RubyFunction { #[derive(Debug, Clone, PartialEq, Eq)] pub struct RubyClass { pub name: String, - pub line: (usize, usize), + pub lines: (usize, usize), pub superclass: Option, pub top: String, pub bottom: String, @@ -67,7 +66,6 @@ pub struct RubyParams { kwnilarg: bool, forwarded_args: bool, /// arg name, default value - optargs: Vec<(String, String)>, kwoptargs: Vec<(String, String)>, kwrestarg: Option, restarg: Option, @@ -79,7 +77,6 @@ impl RubyParams { args: Vec::new(), kwnilarg: false, forwarded_args: false, - optargs: Vec::new(), kwrestarg: None, restarg: None, kwargs: Vec::new(), @@ -90,10 +87,6 @@ impl RubyParams { fn contains(&self, name: &String) -> bool { self.args.contains(name) || self.kwargs.contains(name) - || self - .optargs - .iter() - .any(|(arg, default)| arg == name || default == name) || self .kwoptargs .iter() @@ -112,56 +105,54 @@ pub(crate) fn find_function_in_file( file_contents: &str, name: &str, ) -> Result, Box> { + // TODO: make starts and top of function & classes start from beginning of line so indentation will be correct let parser = Parser::new(file_contents, ParserOptions::default()); let parsed = parser.do_parse(); + // POSSBLE TODO check if there is any error dianostics parsed.dadnostices and return error is so let ast = parsed.ast.unwrap_to_error("Failed to parse file")?; - let fns = get_functions_from_node(&ast, &None, name); + let fns = get_functions_from_node(&ast, &vec![], name); let index = super::turn_into_index(file_contents)?; - fns.iter() + let fns = fns + .iter() .map(|(f, c)| { - let class = match c { - Some(c) => { - let start_line = super::get_from_index(&index, c.expression_l.begin) - .unwrap_to_error("Failed to get start line")?; - let end_line = super::get_from_index(&index, c.expression_l.end) - .unwrap_to_error("Failed to get end line")?; + let class = c + .iter() + .filter_map(|c| { + let start_line = super::get_from_index(&index, c.expression_l.begin)?; + let end_line = super::get_from_index(&index, c.expression_l.end)?; let loc_end = c.end_l; let top = Loc { begin: c.expression_l.begin, - end: c - .body - .as_ref() - .map_or(c.keyword_l.end, |b| b.expression().begin), + end: c.body.as_ref().map_or( + c.superclass + .as_ref() + .map_or(c.name.expression().end, |c| c.expression().end), + |b| b.expression().begin, + ), }; - let mut top = top - .source(&parsed.input) - .unwrap_to_error("Failed to get top of class from source")?; - top = top.trim_end().to_string(); + let mut top = top.source(&parsed.input)?; + top = top.trim_matches('\n').to_string(); top = super::make_lined(&top, start_line); Some(RubyClass { name: parser_class_name(c), - line: (start_line, end_line), + lines: (start_line, end_line), superclass: parse_superclass(c), top, bottom: super::make_lined( - loc_end - .source(&parsed.input) - .unwrap_to_error("Failed to get last line of class source")? - .trim_matches('\n'), + loc_end.source(&parsed.input)?.trim_matches('\n'), end_line, ), }) - } - None => None, - }; + }) + .collect(); let start = f.expression_l.begin; // get the lines from map using f.expression_l.begin and f.expression_l.end - let start_line = - super::get_from_index(&index, start).unwrap_to_error("Failed to get start line")?; + let start_line = super::get_from_index(&index, start) + .unwrap_to_error("Failed to get start lines")?; let end_line = super::get_from_index(&index, f.expression_l.end) .unwrap_to_error("Failed to get end line")?; let starts = start_line + 1; - Ok(RubyFunction { + Ok::>(RubyFunction { name: f.name.clone(), lines: (start_line + 1, end_line + 1), class, @@ -176,17 +167,22 @@ pub(crate) fn find_function_in_file( args: f .args .clone() - .map_or_else(RubyParams::new, |a| parse_args_from_node(&a)), + .map_or_else(RubyParams::new, |a| parse_args_from_node(&a, &parsed.input)), }) }) - .collect() + .filter_map(Result::ok) + .collect::>(); + if fns.is_empty() { + Err("No functions with this name was found in the this file")?; + } + Ok(fns) } fn get_functions_from_node( node: &lib_ruby_parser::Node, - class: &Option, + class: &Vec, name: &str, -) -> Vec<(Def, Option)> { +) -> Vec<(Def, Vec)> { match node { lib_ruby_parser::Node::Def(def) => { if def.name == name { @@ -195,10 +191,12 @@ fn get_functions_from_node( vec![] } } - lib_ruby_parser::Node::Class(class) => { + lib_ruby_parser::Node::Class(new_class) => { let mut functions = vec![]; - for child in &class.body { - functions.extend(get_functions_from_node(child, &Some(class.clone()), name)); + let mut new_list = class.clone(); + new_list.push(new_class.clone()); + for child in &new_class.body { + functions.extend(get_functions_from_node(child, &new_list, name)); } functions } @@ -213,26 +211,23 @@ fn get_functions_from_node( } } -fn parse_args_from_node(node: &lib_ruby_parser::Node) -> RubyParams { - // TODO: make a Args struct has fields {args: Vec, kwargs, kwoptargs, optargs, kwrestargs, block_args, kwnilarg: bool, fowardarg: bool} - // where I didnt annotate a type its needs to be figured out the args purpose and anoatate the type based on that +fn parse_args_from_node(node: &lib_ruby_parser::Node, parsed_file: &DecodedInput) -> RubyParams { let mut ret_args = RubyParams::new(); if let lib_ruby_parser::Node::Args(args) = node { args.args.iter().for_each(|arg| match arg { // basic arg - //python/ruby lib_ruby_parser::Node::Arg(arg) => ret_args.args.push(arg.name.clone()), lib_ruby_parser::Node::Kwarg(arg) => ret_args.kwargs.push(arg.name.clone()), - // args that has a default value - // TODO: get the default value lib_ruby_parser::Node::Kwoptarg(arg) => { - ret_args.kwoptargs.push((arg.name.clone(), String::new())); + ret_args.kwoptargs.push(( + arg.name.clone(), + arg.default + .expression() + .source(parsed_file) + .unwrap_or_else(|| "could not retrieve default value".to_string()), + )); } - lib_ruby_parser::Node::Optarg(arg) => { - ret_args.optargs.push((arg.name.clone(), String::new())); - } - lib_ruby_parser::Node::Restarg(arg) => { if let Some(name) = &arg.name { ret_args.restarg = Some(name.clone()); @@ -247,7 +242,7 @@ fn parse_args_from_node(node: &lib_ruby_parser::Node) -> RubyParams { // ruby specific lib_ruby_parser::Node::ForwardArg(_) => ret_args.forwarded_args = true, lib_ruby_parser::Node::Kwnilarg(_) => ret_args.kwnilarg = true, - // Node::ForwardedArgs and Node::Kwargs are for method calls and not definitions thus we are not matching on them + // Node::ForwardedArgs and Node::Kwargs, node::Optarg are for method calls and not definitions thus we are not matching on them // Node::Blockarg is for block methods similar to labmdas whic we do not currently support _ => {} }); @@ -276,19 +271,25 @@ impl FunctionTrait for RubyFunction { crate::impl_function_trait!(RubyFunction); fn get_total_lines(&self) -> (usize, usize) { - self.class.as_ref().map_or(self.lines, |c| c.line) + self.class + .iter() + .map(|class| class.lines) + .min_by(Ord::cmp) + .unwrap_or(self.lines) } fn get_tops(&self) -> Vec<(String, usize)> { self.class - .as_ref() - .map_or_else(Vec::new, |c| vec![(c.top.clone(), c.line.0)]) + .iter() + .map(|class| (class.top.clone(), class.lines.0)) + .collect() } fn get_bottoms(&self) -> Vec<(String, usize)> { self.class - .as_ref() - .map_or_else(Vec::new, |c| vec![(c.bottom.clone(), c.line.1)]) + .iter() + .map(|class| (class.bottom.clone(), class.lines.1)) + .collect() } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -301,12 +302,9 @@ pub enum RubyFilter { impl RubyFilter { pub fn matches(&self, function: &RubyFunction) -> bool { match self { - Self::FunctionInClass(name) => function - .class - .as_ref() - .map_or(false, |class| *name == class.name), + Self::FunctionInClass(name) => function.class.iter().any(|class| &class.name == name), Self::FunctionWithParameter(name) => function.args.contains(name), - Self::FunctionWithSuperClass(name) => function.class.as_ref().map_or(false, |class| { + Self::FunctionWithSuperClass(name) => function.class.iter().any(|class| { class .superclass .as_ref() diff --git a/git-function-history-lib/src/test_functions.rb b/git-function-history-lib/src/test_functions.rb index 7381033a..be3659bc 100644 --- a/git-function-history-lib/src/test_functions.rb +++ b/git-function-history-lib/src/test_functions.rb @@ -1,16 +1,27 @@ def main() puts "Hello World" end - -def empty_test() +class Banana + class Apple + def empty_test(*a, b, c, d: 1, e: 2, **foo) + end + end + def empty_test(a, c: 1) + end +end +def empty_test(a, **nil) end class SupderDuper def boring end + def empty_test(a, **nil) + end end class Test < SupderDuper - def empty_test() + def empty_test(*b,c, a: ,n: 1, d:true, **foo) + # a,a: ,n: 1, b = true, *bar,**foo + # ) end def test() @@ -19,4 +30,4 @@ def test() end # def () empty_test -# end \ No newline at end of file +# end From d36a9179bb4b2cc3295e2f795e5f50096a62eb1a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 19 Dec 2022 19:00:38 -0500 Subject: [PATCH 163/172] using threadsaferepository so no longer having to sue discover for each commit --- git-function-history-lib/src/lib.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/git-function-history-lib/src/lib.rs b/git-function-history-lib/src/lib.rs index 3ff6cf20..1922cf46 100644 --- a/git-function-history-lib/src/lib.rs +++ b/git-function-history-lib/src/lib.rs @@ -146,6 +146,7 @@ pub fn get_function_history( } // if filter is date list all the dates and find the one that is closest to the date set that to closest_date and when using the first filter check if the date of the commit is equal to the closest_date let repo = git_repository::discover(".")?; + let th_repo = repo.clone().into_sync(); let mut tips = vec![]; let head = repo.head_commit()?; tips.push(head.id); @@ -255,7 +256,7 @@ pub fn get_function_history( let commits = commits.iter(); let commits = commits .filter_map(|i| { - let tree = sender(i.0, name, *langs, file); + let tree = sender(i.0, &th_repo.to_thread_local(), name, *langs, file); match tree { Ok(tree) => { if tree.is_empty() { @@ -305,14 +306,14 @@ impl Default for MacroOpts<'_> { fn sender( id: ObjectId, + repo: &git_repository::Repository, name: &str, langs: Language, file: &FileFilterType, ) -> Result, Box> { - let repo = git_repository::discover(".")?; let object = repo.find_object(id)?; let tree = object.try_into_tree()?; - traverse_tree(&tree, &repo, name, "", langs, file) + traverse_tree(&tree, repo, name, "", langs, file) } fn traverse_tree( @@ -426,6 +427,7 @@ fn traverse_tree( Ok(ret) } + /// macro to get the history of a function /// wrapper around the `get_function_history` function /// From bd7ae0e359cd17062f800a798623d2a9c16ff6e6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 19 Dec 2022 22:39:49 -0500 Subject: [PATCH 164/172] udpated dependcies & readme also fixed bug that made python code skip the last line --- cargo-function-history/Cargo.toml | 4 ++-- git-function-history-gui/src/lib.rs | 1 - git-function-history-lib/Cargo.toml | 10 +++++----- git-function-history-lib/README.md | 7 +++++-- git-function-history-lib/src/languages/python.rs | 2 +- git-function-history-lib/src/test_functions.py | 2 ++ 6 files changed, 15 insertions(+), 11 deletions(-) diff --git a/cargo-function-history/Cargo.toml b/cargo-function-history/Cargo.toml index 78f61f15..e32a94ad 100644 --- a/cargo-function-history/Cargo.toml +++ b/cargo-function-history/Cargo.toml @@ -19,9 +19,9 @@ unstable = ["function_history_backend_thread/unstable", "git_function_history/un [dependencies] git_function_history = { path = "../git-function-history-lib", version = "0.6.2", default-features = false} lazy_static = "1.4.0" -tui = { version = "0.19", features = ["crossterm"], default-features = false } +tui = { version = "0.19.0", features = ["crossterm"], default-features = false } crossterm = "0.25.0" -tokio = { version = "1.22.0", features = ["full"] } +tokio = { version = "1.23.0", features = ["full"] } eyre = "0.6.8" dirs = "4.0.0" simple_file_logger = "0.3.1" diff --git a/git-function-history-gui/src/lib.rs b/git-function-history-gui/src/lib.rs index 8cf1dd7d..f43ff6cc 100644 --- a/git-function-history-gui/src/lib.rs +++ b/git-function-history-gui/src/lib.rs @@ -242,7 +242,6 @@ impl MyEguiApp { } }); }); - // TODO: if no commit is found, show a message if let Some(x) = history.get_mut_commit() { Self::draw_commit(x, ctx, false) } else { diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 503f09c7..d592b310 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -19,8 +19,8 @@ cache = ["dep:cached"] [dependencies] chrono = "0.4.23" -ra_ap_syntax = "0.0.143" -rayon = { version = "1.6.0", optional = true } +ra_ap_syntax = "0.0.144" +rayon = { version = "1.6.1", optional = true } # rustpython-parser = "0.1.2" # for end_lines but can't be publsihed b/c git depenency rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" } @@ -29,7 +29,7 @@ gosyn = {version = "0.2.0", optional = true} # can't be published b/c git dependency # javaparser = {git = "https://github.com/tanin47/javaparser.rs", optional = true} cfg-if = "1.0.0" -cached = {version = "0.40.0", optional = true} +cached = {version = "0.41.0", optional = true} gitoxide-core = "0.21.0" -git-repository = { version = "0.29.0", default-features = false, features = ["max-performance-safe"] } -git-features = { version = "0.24.0", features = ["zlib", "once_cell"] } \ No newline at end of file +git-repository = { version = "0.30.0", default-features = false, features = ["max-performance-safe"] } +git-features = { version = "0.25.0", features = ["zlib", "once_cell"] } \ No newline at end of file diff --git a/git-function-history-lib/README.md b/git-function-history-lib/README.md index be94d87c..326534ff 100644 --- a/git-function-history-lib/README.md +++ b/git-function-history-lib/README.md @@ -19,6 +19,9 @@ Use the latest [crates.io](https://crates.io/crates/git_function_history) by put - cache: enables caching when parsing files that don't change -## known issues +## parsing library dependencies -- python: since the parser only finds the beginning of the function we have to use some workarounds to find the end of the function. This means that if you have a function that anything from the end of one function to either the beginning of another function or the end of the file that is not python code for example a comment it will be included in the function. +| Language | Rust | Ruby | Python | Go | +| --- | --- | --- | --- | --- | +|Source| [ra_ap_syntax](https://crates.io/crates/ra_ap_syntax)([Rust Analyzer](https://rust-analyzer.github.io/)) | [lib-ruby-parser](https://crates.io/crates/lib-ruby-parser) | [rustpython-parser](https://crates.io/crates/rustpython-parser/)([RustPython](https://rustpython.github.io/)) | [gosyn](https://crates.io/crates/gosyn) | +| Requirements | | | | rust nightly and unstable feature | diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index cc4777d4..cbb4379b 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -113,7 +113,7 @@ pub(crate) fn find_function_in_file( .end_location .unwrap_to_error("no end location for this function")? .row(); - let (Some(starts), Some(ends)) = (map.get(&(start - 1)), map.get(&(end - 1))) else { continue }; + let (Some(starts), Some(ends)) = (map.get(&(start - 1)), map.get(&(end))) else { continue }; if let StmtKind::FunctionDef { name, args, diff --git a/git-function-history-lib/src/test_functions.py b/git-function-history-lib/src/test_functions.py index 4c0e87d4..a6c0999d 100644 --- a/git-function-history-lib/src/test_functions.py +++ b/git-function-history-lib/src/test_functions.py @@ -32,6 +32,8 @@ def empty_test(n: int) -> list: """This is an empty test with a docstring""" pass +# def empty_test(n: int) -> list: + class TestClass: def test_method(self): pass From 3dee1b6b62aecd0a4faf118efb0d6a11aa1a89d2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 21 Dec 2022 15:16:15 -0500 Subject: [PATCH 165/172] fixed ruby identation --- .../src/languages/ruby.rs | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index 9713b2af..b8d1da5f 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -1,4 +1,4 @@ -use std::{error::Error, fmt}; +use std::{collections::HashMap, error::Error, fmt}; use lib_ruby_parser::{ nodes::{Class, Def}, @@ -105,7 +105,16 @@ pub(crate) fn find_function_in_file( file_contents: &str, name: &str, ) -> Result, Box> { - // TODO: make starts and top of function & classes start from beginning of line so indentation will be correct + let mut starts = file_contents + .match_indices('\n') + .map(|x| x.0) + .collect::>(); + starts.push(0); + starts.sort_unstable(); + let map = starts + .iter() + .enumerate() + .collect::>(); let parser = Parser::new(file_contents, ParserOptions::default()); let parsed = parser.do_parse(); // POSSBLE TODO check if there is any error dianostics parsed.dadnostices and return error is so @@ -122,13 +131,13 @@ pub(crate) fn find_function_in_file( let end_line = super::get_from_index(&index, c.expression_l.end)?; let loc_end = c.end_l; let top = Loc { - begin: c.expression_l.begin, + begin: **map.get(&(start_line - 1))?, end: c.body.as_ref().map_or( c.superclass .as_ref() .map_or(c.name.expression().end, |c| c.expression().end), |b| b.expression().begin, - ), + ) - 1, }; let mut top = top.source(&parsed.input)?; top = top.trim_matches('\n').to_string(); @@ -139,7 +148,10 @@ pub(crate) fn find_function_in_file( superclass: parse_superclass(c), top, bottom: super::make_lined( - loc_end.source(&parsed.input)?.trim_matches('\n'), + loc_end + .with_begin(**map.get(&(end_line - 1))?) + .source(&parsed.input)? + .trim_matches('\n'), end_line, ), }) @@ -154,15 +166,15 @@ pub(crate) fn find_function_in_file( let starts = start_line + 1; Ok::>(RubyFunction { name: f.name.clone(), - lines: (start_line + 1, end_line + 1), + lines: (start_line, end_line), class, body: super::make_lined( f.expression_l - .with_begin(start) + .with_begin(**map.get(&(start_line - 1)).unwrap_or(&&0)) .source(&parsed.input) .unwrap_to_error("Failed to get function body from source")? .trim_matches('\n'), - starts, + starts - 1, ), args: f .args From 2fbc458867e2fa5ec6eb48bfb4f3502000647b19 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Wed, 21 Dec 2022 20:16:55 +0000 Subject: [PATCH 166/172] update changelog --- CHANGELOG.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08913564..aff25751 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,10 +28,7 @@ All notable changes to this project will be documented in this file. ### Lib -- Moved away from using mostly enerics to using enums - Python works besides for one edge case when the function is the last node -- Non proggraming languge (pl) filters addded back -- Added ability to search in all supported languages - Pl filters now working very messy and boilerplatety - Fixed bug where I didnt understand how cfg-if works, also filter_by macro works just neeeds docs @@ -39,14 +36,12 @@ All notable changes to this project will be documented in this file. - Saving search history to a file now - Shortend filter loc -- Search/filters are fixed was not working b/c of using window(2) - Added more filters ## [2.1.0] - 2022-09-28 ### Library -- Added git filters for commit, aothor and emai, messagel - More parllesim - Trying to optimize threading realizng the problem is not with the trreading but with something else - Added parelel as optinal (but default feature From f3818331f840296d9407cfb44e16148932f0abe0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 21 Dec 2022 20:42:24 -0500 Subject: [PATCH 167/172] added documentaion merging into other-lang-support --- git-function-history-lib/src/languages/go.rs | 11 +++++++---- git-function-history-lib/src/languages/mod.rs | 15 +++++++++++++++ git-function-history-lib/src/languages/python.rs | 9 +++++++++ git-function-history-lib/src/languages/ruby.rs | 14 +++++++++++++- git-function-history-lib/src/types.rs | 12 ++++++++++++ 5 files changed, 56 insertions(+), 5 deletions(-) diff --git a/git-function-history-lib/src/languages/go.rs b/git-function-history-lib/src/languages/go.rs index 972b3389..67fa7051 100644 --- a/git-function-history-lib/src/languages/go.rs +++ b/git-function-history-lib/src/languages/go.rs @@ -4,6 +4,7 @@ use std::{collections::HashMap, error::Error, fmt}; use super::FunctionTrait; #[derive(Debug, Clone)] +/// A Go function pub struct GoFunction { pub(crate) name: String, pub(crate) body: String, @@ -12,10 +13,11 @@ pub struct GoFunction { pub(crate) lines: (usize, usize), } #[derive(Debug, Clone)] +/// The parameters of a Go function pub enum GoParameter { - /// type + /// type parameter Type(Vec), - /// (name, type) + /// named parameter, still has a type (name, type) Named(HashMap), } @@ -198,10 +200,11 @@ pub(crate) fn find_function_in_file( #[derive(Debug, Clone, PartialEq, Eq)] pub enum GoFilter { - // refers to the type of a parameter + // refers to the type of a parameter of a function HasParameter(String), - // refers to the name of a parameter + // refers to the name of a parameter of a function HasParameterName(String), + // refers to the type of the return value of a function HasReturnType(String), } diff --git a/git-function-history-lib/src/languages/mod.rs b/git-function-history-lib/src/languages/mod.rs index 0a43a047..43ed6659 100644 --- a/git-function-history-lib/src/languages/mod.rs +++ b/git-function-history-lib/src/languages/mod.rs @@ -65,6 +65,7 @@ impl Language { } } + /// returns the name of the language(s) pub const fn get_names(&self) -> &str { match self { Self::Python => "python", @@ -81,6 +82,7 @@ impl Language { } } + /// returns the file extensions of the language(s) pub const fn get_file_endings(&self) -> &[&str] { match self { Self::Python => &["py", "pyw"], @@ -122,10 +124,15 @@ pub mod python; pub mod ruby; pub mod rust; +/// trait that all languages functions must implement pub trait FunctionTrait: fmt::Debug + fmt::Display { + /// returns the starting and ending line of the function fn get_lines(&self) -> (usize, usize); + /// returns the starting and ending line of the the function including any class/impls (among others) the function is part of fn get_total_lines(&self) -> (usize, usize); + /// returns the name of the function fn get_name(&self) -> String; + /// returns the body of the function (the whole function including its signature and end) fn get_body(&self) -> String; /// returns the tops like any the heading of classes/impls (among others) the function is part of along with the starting line of each heading /// for example it could return `[("impl Test {", 3)]` @@ -165,8 +172,13 @@ fn make_lined(snippet: &str, mut start: usize) -> String { .to_string() } +/// trait that all languages files must implement pub trait FileTrait: fmt::Debug + fmt::Display { + /// returns the language of the file + fn get_language(&self) -> Language; + /// returns the name of the file fn get_file_name(&self) -> String; + /// returns the found functions in the file fn get_functions(&self) -> Vec>; /// # Errors @@ -245,6 +257,9 @@ macro_rules! make_file { } impl FileTrait for $name { + fn get_language(&self) -> Language { + Language::$filtername + } fn get_file_name(&self) -> String { self.file_name.clone() } diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index cbb4379b..403ef2e5 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -10,6 +10,7 @@ use crate::{impl_function_trait, UnwrapToError}; use super::FunctionTrait; #[derive(Debug, Clone)] +/// A python function pub struct PythonFunction { pub(crate) name: String, pub(crate) body: String, @@ -34,12 +35,18 @@ impl fmt::Display for PythonFunction { } #[derive(Debug, Clone)] +/// A single parameter of a python function pub struct Param { + /// The name of the parameter pub name: String, + /// The optional type of the parameter pub r#type: Option, } #[derive(Debug, Clone)] +/// The parameters of a python function +/// refer to python docs for more info +/// note: currently we don't save default values pub struct PythonParams { pub args: Vec, pub kwargs: Vec, @@ -62,6 +69,7 @@ impl PythonParams { } #[derive(Debug, Clone)] +/// A python class pub struct PythonClass { pub(crate) name: String, pub(crate) top: String, @@ -69,6 +77,7 @@ pub struct PythonClass { pub(crate) decorators: Vec<(usize, String)>, } #[derive(Debug, Clone)] +/// A python function that is a parent of another python function, we don't keep the body of the function pub struct PythonParentFunction { pub(crate) name: String, pub(crate) top: String, diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index b8d1da5f..eb616fab 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -11,6 +11,7 @@ use crate::UnwrapToError; use super::FunctionTrait; #[derive(Debug, Clone, PartialEq, Eq)] +// repersentation of a ruby function pub struct RubyFunction { pub name: String, pub lines: (usize, usize), @@ -51,6 +52,7 @@ impl fmt::Display for RubyFunction { } #[derive(Debug, Clone, PartialEq, Eq)] +/// represents a Ruby class pub struct RubyClass { pub name: String, pub lines: (usize, usize), @@ -60,14 +62,21 @@ pub struct RubyClass { } #[derive(Debug, Clone, PartialEq, Eq)] +/// repersents parameters of a ruby function pub struct RubyParams { + /// required parameters args: Vec, + /// keyword parameters kwargs: Vec, + /// keyword parameter is nil ie `**nil` in `def foo(a, **nil)` kwnilarg: bool, + /// parameters are forwarded ie `...` in `def foo(...)` forwarded_args: bool, - /// arg name, default value + /// parameters that have optional default values ie `a: 1` in `def foo(a: 1)` kwoptargs: Vec<(String, String)>, + /// keyword rest parameter ie `**a` in `def foo(**a)` kwrestarg: Option, + /// rest parameter ie `*a` in `def foo(*a)` restarg: Option, } @@ -306,8 +315,11 @@ impl FunctionTrait for RubyFunction { } #[derive(Debug, Clone, PartialEq, Eq)] pub enum RubyFilter { + /// find a Ruby functions in a specific class FunctionInClass(String), + /// find a Ruby function with a specific parameter FunctionWithParameter(String), + /// find a Ruby function in a class that inherits from a specific class FunctionWithSuperClass(String), } diff --git a/git-function-history-lib/src/types.rs b/git-function-history-lib/src/types.rs index be740c01..a26b6184 100644 --- a/git-function-history-lib/src/types.rs +++ b/git-function-history-lib/src/types.rs @@ -91,6 +91,18 @@ impl FileTrait for FileType { Self::Ruby(file) => file.get_current(), } } + + fn get_language(&self) -> crate::Language { + match self { + Self::Rust(file) => file.get_language(), + Self::Python(file) => file.get_language(), + // #[cfg(feature = "c_lang")] + // Self::C(file) => file.get_language(), + #[cfg(feature = "unstable")] + Self::Go(file) => file.get_language(), + Self::Ruby(file) => file.get_language(), + } + } } impl fmt::Display for FileType { From 608941d961687b2159bf232d78e4f57e6256c37a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 21 Dec 2022 21:03:47 -0500 Subject: [PATCH 168/172] added mmore docs --- git-function-history-lib/src/languages/python.rs | 11 +++++++++++ git-function-history-lib/src/languages/ruby.rs | 2 ++ git-function-history-lib/src/languages/rust.rs | 2 ++ 3 files changed, 15 insertions(+) diff --git a/git-function-history-lib/src/languages/python.rs b/git-function-history-lib/src/languages/python.rs index 403ef2e5..a0cebbe0 100644 --- a/git-function-history-lib/src/languages/python.rs +++ b/git-function-history-lib/src/languages/python.rs @@ -23,13 +23,24 @@ pub struct PythonFunction { } impl fmt::Display for PythonFunction { + /// don't use this for anything other than debugging the output is not guaranteed to be in the right order + /// use `fmt::Displa`y for `PythonFile` instead fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for class in &self.class { + for decorator in &class.decorators { + write!(f, "{}\n...\n", decorator.1)?; + } write!(f, "{}\n...\n", class.top)?; } for parent in &self.parent { + for decorator in &parent.decorators { + write!(f, "{}\n...\n", decorator.1)?; + } write!(f, "{}\n...\n", parent.top)?; } + for decorator in &self.decorators { + write!(f, "{}\n...\n", decorator.1)?; + } write!(f, "{}", self.body) } } diff --git a/git-function-history-lib/src/languages/ruby.rs b/git-function-history-lib/src/languages/ruby.rs index eb616fab..3e809d55 100644 --- a/git-function-history-lib/src/languages/ruby.rs +++ b/git-function-history-lib/src/languages/ruby.rs @@ -39,6 +39,8 @@ impl RubyFunction { } impl fmt::Display for RubyFunction { + /// don't use this for anything other than debugging the output is not guaranteed to be in the right order + /// use `fmt::Display` for `RubyFile` instead fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for class in &self.class { write!(f, "{}", class.top)?; diff --git a/git-function-history-lib/src/languages/rust.rs b/git-function-history-lib/src/languages/rust.rs index 7e5e670e..7070956e 100644 --- a/git-function-history-lib/src/languages/rust.rs +++ b/git-function-history-lib/src/languages/rust.rs @@ -49,6 +49,8 @@ impl RustFunction { } impl fmt::Display for RustFunction { + /// don't use this for anything other than debugging the output is not guaranteed to be in the right order + /// use `fmt::Display` for `RustFile` instead fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.block { None => {} From d60e4daa9424f708125e83737f2098486c67efe0 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Wed, 21 Dec 2022 21:18:25 -0500 Subject: [PATCH 169/172] bumped main lib version & backend threaad version remove/added from some readmes --- README.md | 10 ---------- TODO.md | 2 +- cargo-function-history/Cargo.toml | 4 ++-- function_history_backend_thread/Cargo.toml | 4 ++-- git-function-history-gui/Cargo.toml | 4 ++-- git-function-history-lib/Cargo.toml | 2 +- git-function-history-lib/README.md | 2 +- 7 files changed, 9 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index d6863e61..7cca97d9 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,6 @@ # git function history -## benchmarks - -Parser (main) vs Regex approach benchmarks: -| approach| expensive| relative| date-range | -| --- | --- | --- | --- | -|regex| 313 second(s) | 22 second(s) | 8 second(s) | -|parser| 22 second(s) | 21 second(s)| 1 second(s) | - -* These benchmarks were done in debug mode on a Ryzen 7 5700u with 16Gb of ram. - ## crates in this project * [git-function-history-lib](https://github.com/mendelsshop/git_function_history/tree/main/git-function-history-lib) - the library itself diff --git a/TODO.md b/TODO.md index b13dd550..3559c091 100644 --- a/TODO.md +++ b/TODO.md @@ -46,4 +46,4 @@ - [ ] move language module into its own crate - general: - - [ ] update readmes with feautes and benchamrks specifically the repo & git-function-history-lib readmes + - [/] update readmes with feautes and benchamrks specifically the repo & git-function-history-lib readmes diff --git a/cargo-function-history/Cargo.toml b/cargo-function-history/Cargo.toml index e32a94ad..c27a78b6 100644 --- a/cargo-function-history/Cargo.toml +++ b/cargo-function-history/Cargo.toml @@ -17,7 +17,7 @@ parallel = ["git_function_history/parallel", "function_history_backend_thread/pa unstable = ["function_history_backend_thread/unstable", "git_function_history/unstable"] [dependencies] -git_function_history = { path = "../git-function-history-lib", version = "0.6.2", default-features = false} +git_function_history = { path = "../git-function-history-lib", version = "0.7.0", default-features = false} lazy_static = "1.4.0" tui = { version = "0.19.0", features = ["crossterm"], default-features = false } crossterm = "0.25.0" @@ -26,5 +26,5 @@ eyre = "0.6.8" dirs = "4.0.0" simple_file_logger = "0.3.1" log = "0.4.17" -function_history_backend_thread = { path = "../function_history_backend_thread", version = "0.2.2", default-features = false} +function_history_backend_thread = { path = "../function_history_backend_thread", version = "0.3.0", default-features = false} tui-input = "0.6.1" \ No newline at end of file diff --git a/function_history_backend_thread/Cargo.toml b/function_history_backend_thread/Cargo.toml index 3fbfa1b0..cd7ed9d4 100644 --- a/function_history_backend_thread/Cargo.toml +++ b/function_history_backend_thread/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "function_history_backend_thread" -version = "0.2.2" +version = "0.3.0" edition = "2021" license = "MIT" repository = "https://github.com/mendelsshop/git_function_history/tree/main/function_history_backend_thread" @@ -18,5 +18,5 @@ parallel = ["git_function_history/parallel"] unstable = ["git_function_history/unstable"] [dependencies] -git_function_history = { path = "../git-function-history-lib", version = "0.6.2", default-features = false} +git_function_history = { path = "../git-function-history-lib", version = "0.7.0", default-features = false} log = "0.4.17" diff --git a/git-function-history-gui/Cargo.toml b/git-function-history-gui/Cargo.toml index ca47c0ba..165c0624 100644 --- a/git-function-history-gui/Cargo.toml +++ b/git-function-history-gui/Cargo.toml @@ -18,8 +18,8 @@ unstable = ["git_function_history/unstable", "function_history_backend_thread/un [dependencies] eframe = {version = "0.20.1", features = ["dark-light"]} -git_function_history = { path = "../git-function-history-lib", version = "0.6.2", default-features = false} -function_history_backend_thread = { path = "../function_history_backend_thread", version = "0.2.2", default-features = false} +git_function_history = { path = "../git-function-history-lib", version = "0.7.0", default-features = false} +function_history_backend_thread = { path = "../function_history_backend_thread", version = "0.3.0", default-features = false} simple_file_logger = "0.3.1" log = "0.4.17" image = "0.24.5" \ No newline at end of file diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index d592b310..de71a8f7 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "git_function_history" -version = "0.6.2" +version = "0.7.0" edition = "2021" license = "MIT" repository = "https://github.com/mendelsshop/git_function_history/tree/main/git-function-history-lib" diff --git a/git-function-history-lib/README.md b/git-function-history-lib/README.md index 326534ff..fed434e9 100644 --- a/git-function-history-lib/README.md +++ b/git-function-history-lib/README.md @@ -17,7 +17,7 @@ Use the latest [crates.io](https://crates.io/crates/git_function_history) by put - unstable: enable some parsers that require nightly rust so run `cargo +nightly` to use them -- cache: enables caching when parsing files that don't change +- cache: enables caching when parsing files and folders that don't change as often. ## parsing library dependencies From 4fbc1379c89caa8b45652fb02f9075031db72f12 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Thu, 22 Dec 2022 03:03:59 +0000 Subject: [PATCH 170/172] update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aff25751..a59fe235 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ All notable changes to this project will be documented in this file. - Update changelog - Update changelog - Update changelog +- Update changelog +- Update changelog +- Update changelog +- Update changelog ### TODO From 21bb6a5e2b9201e421001293ed3545b1aa262b48 Mon Sep 17 00:00:00 2001 From: Mendel Rubin Date: Wed, 11 Jan 2023 02:00:57 -0500 Subject: [PATCH 171/172] nearly can publish now that rustpython no longer end_lines no longer require using the git version of rustpython --- cargo-function-history/Cargo.toml | 6 +++--- function_history_backend_thread/Cargo.toml | 4 ++-- git-function-history-gui/Cargo.toml | 6 +++--- git-function-history-lib/Cargo.toml | 18 ++++++++---------- git-function-history-lib/README.md | 2 +- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/cargo-function-history/Cargo.toml b/cargo-function-history/Cargo.toml index 78f61f15..8d8bc204 100644 --- a/cargo-function-history/Cargo.toml +++ b/cargo-function-history/Cargo.toml @@ -17,14 +17,14 @@ parallel = ["git_function_history/parallel", "function_history_backend_thread/pa unstable = ["function_history_backend_thread/unstable", "git_function_history/unstable"] [dependencies] -git_function_history = { path = "../git-function-history-lib", version = "0.6.2", default-features = false} +git_function_history = { path = "../git-function-history-lib", version = "0.7.0", default-features = false} lazy_static = "1.4.0" tui = { version = "0.19", features = ["crossterm"], default-features = false } crossterm = "0.25.0" -tokio = { version = "1.22.0", features = ["full"] } +tokio = { version = "1.24.1", features = ["full"] } eyre = "0.6.8" dirs = "4.0.0" simple_file_logger = "0.3.1" log = "0.4.17" -function_history_backend_thread = { path = "../function_history_backend_thread", version = "0.2.2", default-features = false} +function_history_backend_thread = { path = "../function_history_backend_thread", version = "0.3.0", default-features = false} tui-input = "0.6.1" \ No newline at end of file diff --git a/function_history_backend_thread/Cargo.toml b/function_history_backend_thread/Cargo.toml index 3fbfa1b0..cd7ed9d4 100644 --- a/function_history_backend_thread/Cargo.toml +++ b/function_history_backend_thread/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "function_history_backend_thread" -version = "0.2.2" +version = "0.3.0" edition = "2021" license = "MIT" repository = "https://github.com/mendelsshop/git_function_history/tree/main/function_history_backend_thread" @@ -18,5 +18,5 @@ parallel = ["git_function_history/parallel"] unstable = ["git_function_history/unstable"] [dependencies] -git_function_history = { path = "../git-function-history-lib", version = "0.6.2", default-features = false} +git_function_history = { path = "../git-function-history-lib", version = "0.7.0", default-features = false} log = "0.4.17" diff --git a/git-function-history-gui/Cargo.toml b/git-function-history-gui/Cargo.toml index dfb92b7c..165c0624 100644 --- a/git-function-history-gui/Cargo.toml +++ b/git-function-history-gui/Cargo.toml @@ -17,9 +17,9 @@ parallel = ["git_function_history/parallel", "function_history_backend_thread/pa unstable = ["git_function_history/unstable", "function_history_backend_thread/unstable"] [dependencies] -eframe = {version = "0.19.0", features = ["dark-light"]} -git_function_history = { path = "../git-function-history-lib", version = "0.6.2", default-features = false} -function_history_backend_thread = { path = "../function_history_backend_thread", version = "0.2.2", default-features = false} +eframe = {version = "0.20.1", features = ["dark-light"]} +git_function_history = { path = "../git-function-history-lib", version = "0.7.0", default-features = false} +function_history_backend_thread = { path = "../function_history_backend_thread", version = "0.3.0", default-features = false} simple_file_logger = "0.3.1" log = "0.4.17" image = "0.24.5" \ No newline at end of file diff --git a/git-function-history-lib/Cargo.toml b/git-function-history-lib/Cargo.toml index 2615924e..b83c6d02 100644 --- a/git-function-history-lib/Cargo.toml +++ b/git-function-history-lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "git_function_history" -version = "0.6.2" +version = "0.7.0" edition = "2021" license = "MIT" repository = "https://github.com/mendelsshop/git_function_history/tree/main/git-function-history-lib" @@ -18,17 +18,15 @@ cache = ["dep:cached"] [dependencies] chrono = "0.4.23" -ra_ap_syntax = "0.0.140" -rayon = { version = "1.6.0", optional = true } -# rustpython-parser = "0.1.2" -# for end_lines but can't be publsihed b/c git depenency -rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "f885db8c61514f069979861f6b3bd83292086231" } +ra_ap_syntax = "0.0.148" +rayon = { version = "1.6.1", optional = true } +rustpython-parser = { features = ["lalrpop"], version = "0.2.0" } lib-ruby-parser = "3.0.12" gosyn = {version = "0.2.0", optional = true} # can't be published b/c git dependency # javaparser = {git = "https://github.com/tanin47/javaparser.rs", optional = true} cfg-if = "1.0.0" -cached = {version = "0.40.0", optional = true} -gitoxide-core = "0.21.0" -git-repository = { version = "0.29.0", default-features = false, features = ["max-performance-safe"] } -git-features = { version = "0.24.0", features = ["zlib", "once_cell"] } \ No newline at end of file +cached = {version = "0.42.0", optional = true} +gitoxide-core = "0.22.0" +git-repository = { version = "0.33.0", default-features = false, features = ["max-performance-safe"] } +git-features = { version = "0.26.1", features = ["zlib", "once_cell"] } \ No newline at end of file diff --git a/git-function-history-lib/README.md b/git-function-history-lib/README.md index 929845d8..c26bbe89 100644 --- a/git-function-history-lib/README.md +++ b/git-function-history-lib/README.md @@ -5,7 +5,7 @@ Show the git history of a function or method. Use the latest (beta) version by putting `"git_function_history" = { git = 'https://github.com/mendelsshop/git_function_history' }` in your cargo.toml under `[dependencies]` section. -Use the latest [crates.io](https://crates.io/crates/git_function_history) by putting `git_function_history = "0.6.2"` in your cargo.toml under `[dependencies]` section. +Use the latest [crates.io](https://crates.io/crates/git_function_history) by putting `git_function_history = "0.7.0"` in your cargo.toml under `[dependencies]` section. ## features From 005fd5db94724b827457919cbd8db04ff92d8707 Mon Sep 17 00:00:00 2001 From: mendelsshop Date: Wed, 11 Jan 2023 07:02:31 +0000 Subject: [PATCH 172/172] update changelog --- CHANGELOG.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08913564..aff25751 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,10 +28,7 @@ All notable changes to this project will be documented in this file. ### Lib -- Moved away from using mostly enerics to using enums - Python works besides for one edge case when the function is the last node -- Non proggraming languge (pl) filters addded back -- Added ability to search in all supported languages - Pl filters now working very messy and boilerplatety - Fixed bug where I didnt understand how cfg-if works, also filter_by macro works just neeeds docs @@ -39,14 +36,12 @@ All notable changes to this project will be documented in this file. - Saving search history to a file now - Shortend filter loc -- Search/filters are fixed was not working b/c of using window(2) - Added more filters ## [2.1.0] - 2022-09-28 ### Library -- Added git filters for commit, aothor and emai, messagel - More parllesim - Trying to optimize threading realizng the problem is not with the trreading but with something else - Added parelel as optinal (but default feature