├── astdump.rs ├── resources ├── callgraph_footer.html ├── callgraph_header.html └── css │ └── sourcestyle.css ├── screenshot └── callgraph2.png ├── .gitignore ├── test_input0.rs ├── rf_common.rs ├── .travis.yml ├── scripts ├── gedit │ ├── gedit_example.txt │ └── functions.py ├── rg └── gtksourceview-3.0 │ ├── styles │ ├── codedark.xml │ ├── codedark.xml~ │ ├── light.xml │ ├── light.xml~ │ ├── codelight.xml~ │ └── codelight.xml │ └── language-specs │ └── rust.lang ├── test_input2.rs ├── stuff.rs ├── rsfind.rs ├── test_input.rs ├── rustfindctx.rs ├── README ├── util.rs ├── rfserver.rs ├── text_formatting.rs ├── rf_ast_ut.rs ├── indexpage.rs ├── timer.rs ├── htmlwriter.rs ├── Makefile ├── ioutil.rs ├── crosscratemap.rs ├── visit_rust_ast.rs ├── jumptodefmap.rs ├── codemaput.rs └── unfold.c /astdump.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/callgraph_footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /screenshot/callgraph2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dobkeratops/rustfind/HEAD/screenshot/callgraph2.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | rustfind 3 | *.rs.html 4 | *.rfx 5 | test_input 6 | test_input0 7 | TAGS.emacs 8 | html/* 9 | -------------------------------------------------------------------------------- /test_input0.rs: -------------------------------------------------------------------------------- 1 | 2 | fn main() { 3 | println!("{}", foo().to_str()); 4 | } 5 | 6 | fn foo()->Option { 7 | None 8 | } 9 | -------------------------------------------------------------------------------- /resources/callgraph_header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Callgraph 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /rf_common.rs: -------------------------------------------------------------------------------- 1 | // Commmon use's 2 | pub use collections::HashMap; 3 | pub use std::str; 4 | pub use std::num; 5 | pub use timer::Profiler; 6 | use std::strbuf::StrBuf; 7 | use std::strbuf; 8 | use std::vec::Vec; 9 | use std::vec; 10 | 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | before_install: 2 | - yes | sudo add-apt-repository ppa:hansjorg/rust 3 | - sudo apt-get update 4 | install: 5 | - sudo apt-get install rust-nightly 6 | script: 7 | - make rustfind 8 | 9 | notifications: 10 | email: 11 | - damien.schoof+github@gmail.com 12 | -------------------------------------------------------------------------------- /scripts/gedit/gedit_example.txt: -------------------------------------------------------------------------------- 1 | #external tool invocation for gedit 2 | #requires patched functions.py for GEDIT_CURRENT_COLUMN_NUMBER (see scripts) 3 | #!/bin/sh 4 | cd $GEDIT_CURRENT_DOCUMENT_DIR 5 | echo "rustfind:- " 6 | ~/i7rustfind/rustfind test_input.rs $GEDIT_CURRENT_DOCUMENT_NAME:$GEDIT_CURRENT_LINE_NUMBER:$GEDIT_CURRENT_COLUMN_NUMBER 7 | 8 | 9 | -------------------------------------------------------------------------------- /test_input2.rs: -------------------------------------------------------------------------------- 1 | pub fn foo_bar_test_func(apples:fruit::SomeStruct,(oranges,lemon):(int,int))->int{ 2 | let some_var_name=2*oranges; 3 | let a=SomeLongStructName{v:0}; 4 | println!("a"); 5 | println!("b"); 6 | println!("c"); 7 | veg::another_function(apples.red_value,oranges,lemon); 8 | some_var_name-apples.red_value+lemon+a.v 9 | } 10 | 11 | pub mod fruit { 12 | pub struct SomeStruct{ 13 | red_value:int,green_value:int,blue_value:int 14 | } 15 | } 16 | 17 | pub struct SomeLongStructName {v:int} 18 | 19 | mod veg{ 20 | pub fn another_function(a:int,b:int,c:int)->int { 21 | a+b+c 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /stuff.rs: -------------------------------------------------------------------------------- 1 | extern mod syntax; 2 | 3 | use std::hashmap::HashMap; 4 | 5 | // Sketching out how this could work 6 | // but this information is within libsyntax, ast 7 | // 8 | 9 | //namespace path should include struct,trait,enum 10 | enum IdentifierType { 11 | dirname, 12 | filename, 13 | module_def, 14 | type_def, 15 | enum_def, 16 | struct_def, 17 | trait_def, 18 | function_def, 19 | type_param, 20 | arg_name, 21 | var_name 22 | } 23 | 24 | type NamespaceName=(StrBuf,IdentifierType); 25 | type NamespacePath=Vec; 26 | type Line=int; 27 | type Column=int; 28 | type Filename=StrBuf; 29 | type SourceLocation=(Filename,(Line,Column)); 30 | type SourceSpan=(Filename,(Line,Column),(Line,Column)); 31 | type Identifier=StrBuf; 32 | 33 | 34 | type SymbolDef=(IdentifierType,SourceLocation,~NamespacePath); 35 | type SymbolDefs=HashMap; 36 | 37 | fn namespace_path_at(s:&SourceLocation)->~[NamespacePath]{ 38 | ~[] 39 | } 40 | 41 | fn find_symbol_at(ds:&SymbolDefs,sl:&SourceLocation)->Option 42 | { 43 | let path=namespace_path_at(sl); 44 | let identifier=get_identifier_at(sl); 45 | let syms= 46 | match identifier{ 47 | Some(id)=>get_identifier_def(ds,&id), 48 | None=>None 49 | }; 50 | // find the symbol definition most specific to the namepath here. 51 | // = the most matches moving back 52 | None 53 | } 54 | 55 | fn get_identifier_def(ds:&SymbolDefs, id:&Identifier)->Option<&SymbolDef> { 56 | None 57 | } 58 | 59 | fn get_identifier_at(sl:&SourceLocation)->Option { 60 | Some(~"") 61 | } 62 | 63 | fn find_symbol(ds:&SymbolDefs, id:&Identifier)->Option 64 | { 65 | // look at the current source location, look down the dir hrc 66 | // look at standard paths 67 | // repeat from current source location, back a dir.. 68 | None 69 | } 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /rsfind.rs: -------------------------------------------------------------------------------- 1 | extern crate syntax; 2 | extern crate rustc; 3 | //extern crate extra; 4 | 5 | //pub static ctxtkey: local_data::Key<@DocContext> = &local_data::Key; 6 | 7 | pub macro_rules! if_some { 8 | ($b:ident in $a:expr then $c:expr)=>( 9 | match $a { 10 | Some($b)=>$c, 11 | None=>{} 12 | } 13 | ); 14 | } 15 | pub macro_rules! tlogi{ 16 | ($($a:expr),*)=>(println((file!()+":"+line!().to_str()+": " $(+$a.to_str())*) )) 17 | } 18 | pub macro_rules! logi{ 19 | ($($a:expr),*)=>(println(""$(+$a.to_str())*) ) 20 | } 21 | //macro_rules! dump{ ($a:expr)=>(logi!(fmt!("%s=%?",stringify!($a),$a).indent(2,160));)} 22 | macro_rules! dump{ ($($a:expr),*)=> 23 | ( { let mut txt=~""; 24 | $( { txt=txt.append( 25 | format!("{:s}={:?}",stringify!($a),$a)+",") 26 | } 27 | );*; 28 | logi!(txt); 29 | } 30 | ) 31 | } 32 | 33 | pub macro_rules! if_some { 34 | ($b:ident in $a:expr then $c:expr)=>( 35 | match $a { 36 | Some($b)=>$c, 37 | None=>{} 38 | } 39 | ); 40 | ($b:ident in $a:expr then $c:expr _else $d:expr)=>( 41 | match $a { 42 | Some($b)=>$c, 43 | None=>{$d} 44 | } 45 | ); 46 | } 47 | 48 | 49 | #[deriving(Clone, Eq, Encodable, Decodable)] 50 | pub enum ShowDefMode { 51 | SDM_Line=0, 52 | SDM_LineCol=1, 53 | SDM_Source=2, 54 | SDM_GeditCmd=3 55 | } 56 | 57 | 58 | pub trait MyOption { 59 | fn for_some(&self, f: |&T|); 60 | fn do_some(&self, f: |&T| -> R) -> Option; 61 | } 62 | impl MyOption for Option{ 63 | fn for_some(&self, f: |&T|) { 64 | match self { 65 | &None=>{}, 66 | &Some(ref t)=>f(t) 67 | } 68 | } 69 | fn do_some(&self, f: |&T| -> R)->Option { 70 | match self { 71 | &None=>None, 72 | &Some(ref t)=>Some(f(t)) 73 | } 74 | } 75 | } 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /test_input.rs: -------------------------------------------------------------------------------- 1 | #[allow(dead_code)]; 2 | #[allow(unused_variable)]; 3 | use test_input2::{foo_bar_test_func}; 4 | mod test_input2; 5 | 6 | fn yada(a:int,c:Foo,b:test_input2::fruit::SomeStruct)->StrBuf { a.to_strbuf() } 7 | fn main() { 8 | use test_input2::fruit::{SomeStruct}; 9 | println!("{}", foo_bar_test_func(SomeStruct{red_value:1,green_value:2,blue_value:3},(4,5)).to_str()); 10 | let a=Foo{foo_field_1:2}; 11 | a.my_method(1); 12 | let c=a_cat(3); 13 | let d=Foo{foo_field_1:a.foo_field_1+2}; a.test(); 14 | println!("{}", a.foo_field_1.to_str()); 15 | } 16 | 17 | struct Foo{foo_field_1:int} 18 | struct Bar(int); 19 | struct Baz(int); 20 | impl Foo { 21 | fn my_method(&self,_:int){ print!("{}", "my_method of foo");} 22 | } 23 | 24 | enum Animal { 25 | a_anteater(int), 26 | a_bear(int), 27 | a_cat(int), 28 | a_dog(int), 29 | } 30 | 31 | trait Testable 32 | { fn test(&self); 33 | fn test1(&self); 34 | fn test2(&self); 35 | } 36 | trait DoZ { 37 | fn do_z(&self); 38 | } 39 | 40 | impl Testable for Foo { 41 | fn test(&self) { 42 | println!("{}", self.foo_field_1.to_str()); 43 | } 44 | fn test1(&self) 45 | { 46 | println!("{}", self.foo_field_1.to_str()); 47 | } fn test2(&self) 48 | { 49 | println!("{}", self.foo_field_1.to_str()); 50 | } 51 | 52 | } 53 | impl DoZ for Foo { 54 | fn do_z(&self) { 55 | println!("{}", self.foo_field_1.to_str()); 56 | } 57 | } 58 | 59 | trait SuperTraitTest:Testable+DoZ { 60 | } 61 | struct Pair { a:A,b:B } 62 | 63 | fn gfunc(x:&X) { 64 | let a1=a_anteater(1); 65 | let a2=a_bear(1); 66 | let a3=a_cat(1); 67 | let a4=a_dog(1); 68 | x.test(); 69 | x.do_z(); 70 | } 71 | struct TraitedStructTest { 72 | x:X 73 | } 74 | fn some2(a:Animal) { 75 | match a { 76 | a_cat(x)=> println!("{}", "cat"), 77 | _ => println!("{}", "not a cat") 78 | } 79 | 80 | } 81 | 82 | fn foobarbaz()->Pair,Animal> { 83 | Pair{a:Ok(0),b:a_cat(0)} 84 | } 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /rustfindctx.rs: -------------------------------------------------------------------------------- 1 | use std::local_data; 2 | 3 | use syntax::ast; 4 | use syntax::codemap; 5 | use syntax::parse::token; 6 | use rustc::{driver, middle}; 7 | use rustc::metadata::cstore; 8 | 9 | /// context object for the application; holds structs populated by rustc 10 | pub struct RustFindCtx { 11 | pub crate_: @ast::Crate, 12 | // tycx: middle::ty::ctxt, // todo: lazy and make an Rc, or propogate the lifetimes needed for &.. 13 | // sess: driver::session::Session, 14 | pub ca: driver::driver::CrateAnalysis //todo: tycx is in here! 15 | } 16 | /// accessors for RustFindCtx 17 | impl RustFindCtx { 18 | pub fn codemap<'a>(&'a self)->&'a codemap::CodeMap { self.ca.ty_cx.sess.codemap() } 19 | pub fn session<'a>(&'a self)->&'a driver::session::Session { &self.ca.ty_cx.sess } 20 | pub fn cstore<'a>(&'a self)->&'a cstore::CStore { &self.session().cstore } 21 | pub fn tycx_ref<'a>(&'a self)->&'a middle::ty::ctxt { 22 | return &'a self.ca.ty_cx 23 | } 24 | pub fn tycx_val(self)->middle::ty::ctxt { 25 | return self.ca.ty_cx 26 | } 27 | } 28 | // what was this? 29 | //pub static ctxtkey: local_data::Key<@RustFindCtx> = &local_data::Key; 30 | 31 | pub fn first_file_name(dc:&RustFindCtx)->StrBuf { 32 | let files = dc.codemap().files.borrow(); 33 | files.get(0).name.to_strbuf() // clone? 34 | } 35 | 36 | pub fn find_file_name_in(dc:&RustFindCtx,fname:&str)->Option { 37 | // todo subsequence match.. 38 | // TODO - is there an existing way of doing this, "index_of.." ..contains()..? 39 | let files = dc.codemap().files.borrow(); 40 | for f in files.iter() { 41 | if fname==f.name.as_slice() {return Some(fname.to_strbuf());} 42 | } 43 | None 44 | } 45 | 46 | 47 | pub fn get_source_loc(dc:&RustFindCtx, pos:codemap::BytePos)->codemap::Loc { 48 | dc.codemap().lookup_char_pos(pos) 49 | } 50 | 51 | 52 | pub fn str_of_opt_ident(id:Option)->StrBuf{ 53 | match id { 54 | Some(i)=>token::get_ident(i).get().to_strbuf(), None=>StrBuf::new() 55 | } 56 | } 57 | 58 | pub fn str_of_ident(id:ast::Ident)->StrBuf{ 59 | token::get_ident(id).get().to_strbuf() 60 | } 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Uses rust libsyntax to find symbol definitions 2 | and generates HTML view of source with links 3 | finds struct-defs, functions, methods, fields 4 | writes ast node def info into '.rfx' files in plaintext. 5 | Also spits out a graphviz dotfile with the static callgraph, modules as clusters. 6 | 7 | "make" to compile and run test program 8 | "make rustsrc" to generate HTML source for the main rust source tree at $(RUST_PATH)/src 9 | ./rustfind -h to display options 10 | 11 | ./rustfind cratename.rs sourcefile.rs:line:col 12 | ... compiles 'cratename.rs',then shows the 13 | location&definition referenced by sourcefile:line:col 14 | 15 | ./rustfind -j cratename.rs -- dump spans & node definition links as JSON 16 | 17 | ./rustfind -w cratename.rs -- creates HTML view of sourcecode 18 | 19 | roadmap 20 | [1] a commandline tool rustfind sourcefile.rs:LINE:COLUMN: --> definition.rs:LINE:col 21 | (to add add hoc navigation tools eg gedit external tools) 22 | [.1] CTAGS generation ?? 23 | [.1] interactive commandline tool (enter src/location/symbol-> dump location) 24 | [.2] possibly queries like "list all the functions that use this type, list all the impls' for this type.." 25 | [.3] links to Rustdoc ? 26 | 27 | [2] JSON / or other dump 28 | .. are there any formats IDE's read for their indexers? 29 | 30 | [3] options to dump/pretty print more context for the definitoon 31 | 32 | [4] an html hyperlinked source generator, like woboq? 33 | ... + popup type annotaions? 34 | 35 | 36 | [5] use components for IDE integration? 37 | 38 | example of callgraph output 39 | ![Screenshot](screenshot/callgraph2.png) 40 | 41 | Notes on sourcecode:- 42 | -------------------- 43 | -find_ast_node contains the node scanning 44 | -borrows code from rustdoc_ng 45 | -there might be a fair amoount of repition with the compiler internals eg ast node wrappers, 46 | this can be cleaned up.. 47 | -a lot here would factor out if ctxt had a node_id:span map 48 | 49 | Other:- 50 | ------- 51 | improved syntax highlighting rust.lang & required styles (for gtksourceview) included in scripts 52 | 53 | more ideas 54 | 55 | can ctags actually deal with overloaded symbols? 56 | could we write out an intermediate that editors can read for fast jump-to-def, with some dynamic context .. 57 | 58 | 59 | .rfx format: 60 | ------------ 61 | libname node_id source-file-name line col length kind [identifier] 62 | jdef nodeid libname def_node_id 63 | -------------------------------------------------------------------------------- /util.rs: -------------------------------------------------------------------------------- 1 | use std::vec::Vec; 2 | use std::strbuf::StrBuf; 3 | 4 | pub fn text_line_pos_to_offset(text: &[u8], (line, ofs_in_line): (u32, u32))->Option { 5 | // line as reported by grep & text editors,counted from '1' not '0' 6 | let mut pos = 0; 7 | let tlen=text.len() as u32; 8 | let mut tline=0; 9 | let mut line_start_pos = 0; 10 | while pos {tline+=1; line_start_pos=pos;}, 13 | // "\a" => {tpos=0;line_pos=pos;}, 14 | _ => {} 15 | } 16 | // todo - clamp line end 17 | if tline==(line-1){ 18 | return Some(line_start_pos + ofs_in_line); 19 | } 20 | pos+=1; 21 | } 22 | return None; 23 | } 24 | 25 | pub fn get_filename_only(fnm:&str)->StrBuf { 26 | let toks:Vec<&str> =fnm.split(':').collect(); 27 | return (*toks.get(0)).to_strbuf(); 28 | } 29 | 30 | 31 | pub fn text_offset_to_line_pos(text:&[u8], src_ofs: u32)-> Option<(u32, u32)> { 32 | // line as reported by grep & text editors,counted from '1' not '0' 33 | let mut pos = 0; 34 | let tlen = text.len() as u32; 35 | let mut tline=0; 36 | let mut line_start_pos=0; 37 | while pos { 40 | if src_ofs<=pos && src_ofs>line_start_pos { 41 | return Some((tline+1,src_ofs-line_start_pos)); 42 | } 43 | tline+=1; line_start_pos=pos; 44 | }, 45 | // "\a" => {tpos=0;line_pos=pos;}, 46 | _ => {} 47 | } 48 | // todo - clamp line end 49 | pos+=1; 50 | } 51 | return None; 52 | } 53 | pub fn flatten_to_str(xs:&[T],f: |&T| -> U, sep:&str)->StrBuf { 54 | let mut acc=StrBuf::new(); 55 | let mut i=0; // TODO - functional way. 56 | while i0 {acc.push_str(sep);} 58 | acc.push_str( f(&xs[i]).to_str() ); 59 | 60 | i+=1; 61 | } 62 | acc.as_slice().to_strbuf() 63 | } 64 | 65 | pub fn flatten_to_str_ng(xs: &Vec, f: |&T| -> U, sep: &str) -> StrBuf { 66 | // use std::str::with_capacity; 67 | 68 | if xs.is_empty() { return StrBuf::from_str(""); } 69 | 70 | // this calculation is not right, but not sure what the best approximation is 71 | // code taken originally from StrVector code for collect() 72 | let len = sep.len() * (xs.len() * 2 - 1); 73 | let mut result = StrBuf::with_capacity(len); 74 | let mut first = true; 75 | 76 | for s in xs.iter() { 77 | if first { 78 | first = false; 79 | } else { 80 | result.push_str(sep); 81 | } 82 | result.push_str(f(s).to_str()); 83 | } 84 | result 85 | } 86 | -------------------------------------------------------------------------------- /rfserver.rs: -------------------------------------------------------------------------------- 1 | use rustfindctx::{RustFindCtx,find_file_name_in,first_file_name}; 2 | use jumptodefmap::{dump_json,lookup_def_at_text_file_pos_str, make_jump_to_def_map}; 3 | use find_ast_node::def_of_symbol_to_str; 4 | use std::io; 5 | use std::io::BufferedReader; 6 | use rsfind::{SDM_Source}; 7 | use ioutil::ResultUtil; 8 | /* 9 | interactive mode, also server for IDE integration with command interface 10 | */ 11 | 12 | pub fn run_server(dc:&RustFindCtx) { 13 | // TODO - check if RUSTI can already do this.. it would be better there IMO 14 | // todo _ why is super needed here?! 15 | 16 | // Currently unused 17 | let (node_spans,node_def_node,_)=make_jump_to_def_map(dc); 18 | 19 | let mut curr_file=first_file_name(dc); 20 | 21 | println!("rustfind interactive server; type h for help"); 22 | loop { 23 | print!("rustfind {}> ", curr_file); 24 | ::std::io::stdio::flush(); 25 | let input_line=BufferedReader::new(io::stdin()).read_line().expect("read_line failed on stdin"); 26 | let toks:Vec<&str> =input_line.words().collect(); 27 | if toks.len()>0 { 28 | match *toks.get(0) { 29 | "h" | "help" | "?" => 30 | println!("interactive mode\n - enter file:line:pos or line:pos for current file\n - show location & def of symbol there\n j-dump json q-quit i-info"), 31 | "i"=> { 32 | println!("files in current crate:-"); 33 | let files = dc.codemap().files.borrow(); 34 | for x in files.iter() { 35 | println!("\t{}", x.name); 36 | } 37 | } 38 | "j"=> dump_json(dc), 39 | "q"=> break, 40 | _ =>{ 41 | // todo - if you just supply line, lookup defs on that line 42 | // todo - lookup defs from symbol, remembering context of previous lookups? 43 | let cmd=*toks.get(0); 44 | let cmd1 = match cmd.chars().nth(0).unwrap_or('\0') { 45 | '0'..'9' => StrBuf::new().append(curr_file.as_slice()).append(":").append(cmd), 46 | _ => cmd.to_strbuf() 47 | }; 48 | let subtoks:Vec<&str> =cmd1.as_slice().split(':').collect(); 49 | curr_file=find_file_name_in(dc, *subtoks.get(0)).unwrap_or(curr_file); 50 | //dump!(cmd1,subtoks,curr_file); 51 | let def=lookup_def_at_text_file_pos_str(dc, cmd1.as_slice(), SDM_Source); 52 | println!("{}", def.unwrap_or(StrBuf::from_str("no def found"))); 53 | println!("{}", def_of_symbol_to_str(dc, &node_spans,node_def_node,*toks.get(0))); 54 | } 55 | } 56 | } 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /scripts/rg: -------------------------------------------------------------------------------- 1 | if [ -z "$RUST_SRC" ]; then 2 | echo "Rust Grep helper " 3 | export RUST_SRC as standard rust source tree to search 4 | fi 5 | if [ ! "$1" ]; then 6 | echo "Rust Grep helper " 7 | echo "useage rg [unfold opts]" 8 | echo " " 9 | echo "searches for whole word following fn/struct/fn/trait/impl/type, and unfolds results" 10 | echo "optionally provide more options to unfold eg -Su singleline output" 11 | echo "searches *.rs in current location and $RUST_SRC recursively" 12 | echo " " 13 | echo "rg (struct|fn|trait|impl|enum|mod|type|for|method|ret|arg|field|def) Foo [unfold opts]-- search only for struct/fn/etc" 14 | echo "rg method : finds fn (.*self.*) )" 15 | echo "rg for : finds impl for i.e. a function returning 'name')" 16 | echo "rg ret : finds ->.* i.e. a function returning 'name')" 17 | echo "rg arg : finds fn.*(.*.*) i.e. a function taking an argument 'name')" 18 | echo "rg def : just finds (fn|trait|impl|type|mod|for) .. default rg greps if it can't find)" 19 | echo "rg grep : plain grep in rust dirs" 20 | 21 | else 22 | if [ "$1" == "struct" ] || [ $1 == "fn" ] || [ $1 == "impl" ] || [ $1 == "trait" ] || [ $1 == "enum" ] || [ $1 == "mod" ] || [ $1 == "enum" ] || [ $1 == "type" ] || [ $1 == "for" ] || [ $1 == "method" ] || [ $1 == "ret" ] || [ $1 == "arg" ] || [ $1 == "field" ] || [ $1 == "def" ] || [ $1 == "for" ] || [ $1 == "grep" ] ; then 23 | echo "search for $1 def only" 24 | if [ $1 == "impl" ] && [ $3 == "for" ] ; then 25 | echo "Find impl $2 for $4 " 26 | grep -rn "\bimpl.*\s.*$2.*\s*for\s.*$4.*\b" . $RUST_SRC --include "*.rs" | unfold $4 27 | elif [ $1 == "method" ] ; then 28 | grep -rn "\bfn\s*$2\b\s*(.*\bself\b" . $RUST_SRC --include "*.rs" | unfold $3 29 | elif [ $1 == "ret" ] ; then 30 | grep -rn "\->.*$2" . $RUST_SRC --include "*.rs" | unfold $3 31 | elif [ $1 == "arg" ] ; then 32 | grep -rn "\bfn\b.*\(.*$2.*\)" . $RUST_SRC --include "*.rs" | unfold $3 33 | elif [ $1 == "field" ] ; then 34 | grep -rn "\b$2\b\s*:[^:]\b" . $RUST_SRC --include "*.rs" | unfold $3 35 | elif [ $1 == "def" ] ; then 36 | grep -rn "\(trait\|struct\|fn\|impl\|impl.*for\|type\|enum\|macro_rules!\)\s*$2\b" . $RUST_SRC --include "*.rs" | unfold $2 37 | elif [ $1 == "grep" ] ; then 38 | grep -rn $2 . $RUST_SRC --include "*.rs" | unfold $3 39 | else 40 | 41 | grep -rn "\b$1\s*$2\b" . $RUST_SRC --include "*.rs" | unfold $3 42 | fi 43 | else 44 | if [ -n $2 ] ; then 45 | echo "2nd param.." 46 | if [ $2 == "for" ] ; then 47 | echo "Find impl $1 for $3 " 48 | grep -rn "\bimpl.*\s\s*.*$1.*\s*for\s\s*.*$3.*\b" . $RUST_SRC --include "*.rs" | unfold $3 49 | exit 50 | fi 51 | fi 52 | if !( grep -rn "\(trait\|struct\|fn\|fn.*(.*:.*\|impl\|impl.*for\|type\|enum\|macro_rules!\)\s*$1\b" . $RUST_SRC --include "*.rs" | unfold $2 );then 53 | grep -rn "^\s$1\s*[,\n=(\{]" . $RUST_SRC --include "*.rs" 54 | fi 55 | fi 56 | # grep -rn "\(^\s*\|\(trait\|struct\|fn\|impl\|type\|enum\|macro_rules!\)\)\s*$1[^a-zA-Z0-9_]" . $RUST_SRC --include "*.rs" | unfold $2 57 | 58 | 59 | fi 60 | 61 | -------------------------------------------------------------------------------- /text_formatting.rs: -------------------------------------------------------------------------------- 1 | 2 | /// tags: pretty print,code formatting,brace indentation, json braces, brackets,nesting 3 | pub trait Indent { 4 | fn indent(&self,tab_size:int,max_line_size:int)->Self; 5 | } 6 | 7 | impl Indent for StrBuf { 8 | fn indent(&self,tabsize:int, linesize:int)->StrBuf { 9 | // todo-write as iterators. 10 | fn change_indent(c:u8)->int{ 11 | match c as char { 12 | '{'|'('|'['=> 1, 13 | '}'|')'|']'=> -1, 14 | _ => 0 15 | } 16 | } 17 | let mut a=StrBuf::from_str(""); 18 | let mut i=0; 19 | let mut indent=0; 20 | let len=self.len(); 21 | while i=indent && ii= linesize {break}; 38 | cur_linesize+=1; 39 | let di=change_indent(c); 40 | if di>0 && inner_brace_level==indent {last_open=ii;}; 41 | inner_brace_level+=di; 42 | if inner_brace_level==indent { 43 | if di<0 ||c==','as u8||c==';'as u8 { 44 | last_open=ii; 45 | } 46 | 47 | if c==','as u8||c==';'as u8 && first_base_delim==len { 48 | //first_base_delim=ii; 49 | } 50 | } 51 | ii+=1 52 | } 53 | { 54 | let mut ii=0; 55 | while ii=init_indent && i<=first_base_delim && i<=last_open{ 64 | let c=self.as_bytes()[i]; 65 | indent+=change_indent(c); 66 | a.push_char(c as char); 67 | i+=1; 68 | } 69 | } 70 | else { 71 | // copy the line until the lines' last opening 72 | while i=init_indent && i<=last_open && i<=first_base_delim{ 73 | let c=self.as_bytes()[i]; 74 | indent+=change_indent(c); 75 | a.push_char(c as char); 76 | i+=1; 77 | } 78 | } 79 | a.push_char('\n'); 80 | } 81 | a 82 | } 83 | } 84 | 85 | -------------------------------------------------------------------------------- /resources/css/sourcestyle.css: -------------------------------------------------------------------------------- 1 | maintext {color:#f0f0f0; font-size:12px; font-family:"monospace"} 2 | a:link{ color:inherit; font-style:inherit; text-decoration:none;} 3 | a:visited{ color:inherit; font-style:inherit; text-decoration:none;} 4 | a:link:hover{ color:inherit; font-style:inherit; background-color:#606060; } 5 | pr{font-weight:bold} 6 | 7 | /*line numbers*/ 8 | ln{color:#606060; -moz-user-select:-moz-none; -khtml-user-select:none; -webkit-user-select:none; -ms-user-select:none; user-select:none;} 9 | 10 | /* main text*/ 11 | c1{color:#f0ffff; } 12 | /* lesser text*/ 13 | c2{color:#f0ffff; opacity:0.75} 14 | /* delimeters*/ 15 | c3{color:#f090f0; opacity:0.92} 16 | /* special delmeters*/ 17 | c4{color:#fff080; } 18 | /* operators */ 19 | c5{color:#50ff80; } 20 | /* Special operators */ 21 | c6{color:; } 22 | /* type-params */ 23 | c7{color:#60f0c0} 24 | /* Types */ 25 | c8{color:#50e0ff} 26 | /* BuiltInTypes */ 27 | c9{color:#c0d0e0} 28 | 29 | /* methodcall*/ 30 | c10{color:#ffffff} 31 | c11{color:#c0f070} 32 | /* literals */ 33 | c12{color:#ffd000} 34 | /* macros */ 35 | c13{color:#ffc0a0} 36 | /* tuples?*/ 37 | c14{color:#f0ffc0} 38 | c15{color:#f0f0e0} 39 | /* local expr */ 40 | c16{color:#c0ffd0} 41 | c17{color:#90d0f0} 42 | c18{color:#f0a0d0} 43 | c19{color:#d0f0a0} 44 | c20{color:#f0f0ff} 45 | c21{color:#d0d0d0; font-weight:bold} /* structural keywords */ 46 | c22{color:#c0ffd0; } 47 | c23{color:#d0f0ff; } 48 | /*-field*/ 49 | c24{color:#e0ffe0} 50 | c25{color:#fff0d0} 51 | c26{color:#e0d0f0} 52 | c27{color:#70f0f0} 53 | c27{color:#e0e0ff} 54 | 55 | 56 | /* declarative keywords*/ 57 | /* todo, how do css mixins work? */ 58 | /* fn */ 59 | c30{color:#ffffff; font-weight:bold } 60 | /* struct */ 61 | c31{color:##d0ffc0; font-weight:bold } 62 | /* trait */ 63 | c32{color:#c0f0ff; font-weight:bold } 64 | /* impl */ 65 | c33{color:#ffd0e0; font-weight:bold } 66 | /* enum */ 67 | c34{color:#c0ffff; font-weight:bold } 68 | /* type */ 69 | c35{color:##80c0ff; font-weight:bold } 70 | /* static */ 71 | c36{color:#f0c0ff; font-weight:bold } 72 | /* macro */ 73 | c37{color:#ffc0a0; font-weight:bold } 74 | /* mod/ns */ 75 | c38{color:#f0e0ff; font-weight:bold } 76 | /* class/if we do c++ */ 77 | c39{color:#f0e0ff; font-weight:bold } 78 | 79 | /* comment levels*/ 80 | c40{color:#ffffff; font-style:italic; opacity:0.4} 81 | c41{color:#ffffff; font-style:italic; opacity:0.5} 82 | c42{color:#ffffff; font-style:italic; opacity:0.6} 83 | 84 | /* preprocessor/attributes*/ 85 | c50{color:#e0a0d0; } 86 | 87 | /* backgrounds*/ 88 | /* todo, how to select body from these */ 89 | 90 | bg0{background-color:#383838;} 91 | bg1{background-color:#34383c;} 92 | bg2{background-color:#3c3834;} 93 | bg3{background-color:#383c34;} 94 | bg4{background-color:#343c38;} 95 | bg5{background-color:#38343c;} 96 | bg6{background-color:#3a343a;} 97 | bg7{background-color:#3a343a;} 98 | bg8{background-color:#36363a;} 99 | bg9{background-color:#363a36;} 100 | bg10{background-color:#3a3636;} 101 | bg11{background-color:#3a3a34;} 102 | bg12{background-color:#3a333a;} 103 | bg13{background-color:#343a3a;} 104 | bg14{background-color:#343a3c;} 105 | bg15{background-color:#343838;} 106 | 107 | body {background-color:#303030;} 108 | 109 | /* non-source */ 110 | fileblock {background-color:#303030;} 111 | refblock {background-color:#300030;} 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /rf_ast_ut.rs: -------------------------------------------------------------------------------- 1 | use syntax::{ast,ast_map}; 2 | use rustc::middle::ty; 3 | 4 | pub fn get_def_id(curr_crate:ast::CrateNum,src_def:ast::Def)->Option { 5 | let mk=|x|{Some(ast::DefId{krate:curr_crate, node:x})}; // todo,mmaybe this is best 'None'.. 6 | // todo-'definition' can be at multiple locations. we should return [def_id] really.. 7 | match src_def { 8 | ast::DefFn(d,_)=>Some(d), 9 | ast::DefStaticMethod(d,_,_)=>Some(d), 10 | ast::DefSelfTy(id)=>mk(id), 11 | ast::DefMod(d)=>Some(d), 12 | ast::DefForeignMod(d)=>Some(d), 13 | ast::DefStatic(d,_)=>Some(d), 14 | ast::DefArg(id,_)=>mk(id), 15 | ast::DefLocal(id,_)=>mk(id), 16 | ast::DefVariant(_, d2, _)=>Some(d2), 17 | ast::DefTy(d)=>Some(d), 18 | ast::DefTrait(d)=>Some(d), 19 | ast::DefPrimTy(_)=>None, 20 | ast::DefTyParam(d,_)=>Some(d), 21 | ast::DefBinding(d,_)=>mk(d), 22 | ast::DefUse(d)=>Some(d), 23 | ast::DefUpvar(_,d,_,_)=>get_def_id(curr_crate,*d), 24 | ast::DefStruct(d)=>Some(d), 25 | ast::DefTyParamBinder(id)=>mk(id), 26 | ast::DefRegion(id)=>mk(id), 27 | ast::DefLabel(id)=>mk(id), 28 | ast::DefMethod(d,_)=>Some(d) 29 | } 30 | } 31 | 32 | 33 | 34 | pub fn auto_deref_ty<'a> (t: &'a ty::t_box_) -> &'a ty::t_box_ { 35 | match t.sty { 36 | ty::ty_box(p) 37 | | ty::ty_uniq(p) => { 38 | ty::get(p) 39 | }, 40 | ty::ty_ptr(p) 41 | | ty::ty_rptr(_, p) => { 42 | ty::get(p.ty) 43 | }, 44 | _ => t 45 | } 46 | } 47 | 48 | 49 | pub fn dump_ctxt_def_map(tycx: &ty::ctxt) { 50 | // let a:()=ctxt.tycx.node_types 51 | logi!("===Test ctxt def-map table..==="); 52 | let def_map = tycx.def_map.borrow(); 53 | for (key,value) in def_map.iter(){ 54 | dump!(key,value); 55 | } 56 | } 57 | 58 | /* 59 | pub fn dump_methods_of_t(tycx:ty::ctxt, t:*ty::t_opaque) { 60 | for (&k,&method) in tycx.methods.iter() { 61 | dump!(method.transformed_self_ty, t); 62 | if method.transformed_self_ty==Some(t) { 63 | dump!(method); 64 | } 65 | } 66 | 67 | } 68 | 69 | pub fn dump_methods_of_type(tycx:ty::ctxt, type_node_id:ast::NodeId) { 70 | let ot = tycx.node_types.find(&(type_node_id as uint)); 71 | match ot { 72 | None=> {}, 73 | Some(t)=> { 74 | for (&k,&method) in tycx.methods.iter() { 75 | dump!(method.transformed_self_ty, ot); 76 | if method.transformed_self_ty==Some(*t) { 77 | dump!(method); 78 | } 79 | } 80 | } 81 | } 82 | } 83 | */ 84 | 85 | 86 | pub fn get_struct_def<'a,'b>(tc:&'a ty::ctxt, struct_node_id:ast::NodeId)->Option<(@ast::Item,@ast::StructDef,ast::Generics)> { 87 | match tc.map.find(struct_node_id) { 88 | None=>{None}, 89 | Some(node)=>match node { 90 | ast_map::NodeItem(item)=>{ 91 | match item.node { 92 | ast::ItemStruct(sd, ref generics)=>Some((item, sd, generics.clone())), 93 | _=>None 94 | } 95 | } 96 | _=> None 97 | }, 98 | } 99 | } 100 | 101 | pub fn find_named_struct_field(tc:&ty::ctxt, struct_node_id:ast::NodeId, field_ident:&ast::Ident)->Option { 102 | match get_struct_def(tc,struct_node_id) { 103 | None=>None, 104 | Some((_, sd, _))=>{ 105 | for f in sd.fields.iter() { 106 | match f.node.kind { 107 | ast::NamedField(ref ident, _)=>if ident.name ==field_ident.name {return Some(ast::DefId{krate:0,node:f.node.id});}, 108 | _=>return None 109 | } 110 | } 111 | None 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /indexpage.rs: -------------------------------------------------------------------------------- 1 | use rust2html::htmlwriter::HtmlWriter; 2 | use std::str; 3 | use std::io::{File, UserDir}; 4 | use std::io::fs::{mkdir_recursive,copy,walk_dir}; 5 | use collections::hashmap::HashMap; 6 | use collections::hashmap::HashSet; 7 | use rust2html; 8 | use std::cmp; 9 | use std::vec::Vec; 10 | 11 | 12 | // create index page. Show subdirectories and files matching extentions. 13 | // each subdirectory links to the subdir.html 14 | // each listed file links to its 'file.html'. 15 | 16 | 17 | pub fn write_index_html(source_dir: &Path,extentions:&Vec, options:&::RF_Options) { 18 | 19 | //println!("output dir={}",options.output_dir.as_str().unwrap_or("")); 20 | println!("Generating index page:-"); 21 | 22 | // Display all files in the directory tree, 23 | // under the containing directory paths. 24 | let mut files_per_dir=HashMap:: >::new(); 25 | let mut all_dirs = HashSet::::new(); 26 | match walk_dir(source_dir) { 27 | Ok(mut dirs)=> { 28 | for path in dirs { 29 | match path.as_str() { 30 | Some( ref s)=> { 31 | let ext=path.extension_str().unwrap_or("");; 32 | let filename=path.filename_str().unwrap_or(""); 33 | let dirname=path.dirname_str().unwrap_or("./"); 34 | if ext=="rs" { 35 | let link_target= StrBuf::new() 36 | .append(path.as_str().unwrap_or("").to_strbuf().as_slice()).append(".html"); 37 | if Path::new(link_target.as_slice()).exists() || true{ // TODO - why doesn't this filter work now? 38 | all_dirs.insert(dirname.to_strbuf()); 39 | let bucket=files_per_dir.find_or_insert( 40 | dirname.to_strbuf(), 41 | Vec::<(StrBuf,StrBuf)>::new() 42 | ); 43 | // does the file we link to actually exist? 44 | bucket.push( (filename.to_strbuf(), link_target) ); 45 | } 46 | 47 | } 48 | } 49 | None=>{}, 50 | } 51 | } 52 | }, 53 | _=>{} 54 | }; 55 | 56 | let mut doc=HtmlWriter::new(); 57 | let index_path = options.output_dir.join(Path::new("index.html")); 58 | rust2html::write_head(&mut doc, &index_path, options); 59 | 60 | doc.begin_tag_check("body"); 61 | doc.begin_tag("div"); 62 | doc.begin_tag_check("maintext"); 63 | 64 | doc.writeln("Index of " + source_dir.as_str().unwrap_or("")); 65 | 66 | 67 | doc.begin_tag("c40").writeln(rust2html::get_git_branch_info().as_slice()).end_tag(); 68 | 69 | if options.write_callgraph { 70 | doc.begin_tag_link("callgraph.html"); 71 | doc.write("callgraph"); 72 | doc.end_tag(); 73 | } 74 | 75 | let mut all_dirs_sort:Vec<_> = Vec::new(); 76 | 77 | for dir in all_dirs.iter() { 78 | all_dirs_sort.push(dir.clone()); 79 | } 80 | all_dirs_sort.sort(); 81 | 82 | for dir in all_dirs_sort.iter() { 83 | // for (_, files) in files_per_dir.find(dir).aiter() { 84 | let files = files_per_dir.find(dir).unwrap(); 85 | doc.writeln(""); 86 | doc.begin_tag("c30"); doc.writeln(dir.as_slice()); doc.end_tag(); 87 | 88 | write_grid_of_text_links(&mut doc,files); 89 | 90 | } 91 | 92 | // write as grid, todo abstract it ffs. 93 | // TODO we're writing HTML, ffs, its got tables and all sorts.. 94 | // TODO: Grid Layout - seperate path/filename to make squarer items. 95 | 96 | 97 | // write_grid_of_text_links(&mut doc,&links); 98 | 99 | doc.end_tag(); 100 | doc.end_tag(); 101 | doc.end_tag(); 102 | 103 | rust2html::file_write_bytes_as(&index_path, doc.as_bytes()); 104 | } 105 | 106 | fn write_grid_of_text_links(doc:&mut HtmlWriter, links:&Vec<(StrBuf,StrBuf)>) { 107 | let mut max_line_len:uint=1; 108 | for &(ref name,ref link) in links.iter() { 109 | max_line_len =cmp::max(max_line_len, name.len()+1) 110 | } 111 | let desired_width=120; 112 | let num_cols = desired_width / max_line_len; 113 | 114 | let mut column=0; 115 | for &(ref name,ref link) in links.iter() { 116 | doc.begin_tag_link(link.as_slice()); 117 | doc.write(name.as_slice()); 118 | doc.end_tag(); 119 | let mut i=name.len(); 120 | while i=num_cols { 123 | doc.write_tag("br"); 124 | column=0; 125 | } 126 | } 127 | if column!=0 { 128 | doc.write_tag("br"); 129 | } 130 | 131 | } 132 | 133 | 134 | /* 135 | pub fn write_index_html_sub(source_dir:&Path, contents:[&Path]{ 136 | doc = htmlwrite::HtmlWriter::new(); 137 | ::rust2html::write_head(doc, source_dir+"/index.html"); 138 | 139 | }*/ 140 | -------------------------------------------------------------------------------- /timer.rs: -------------------------------------------------------------------------------- 1 | //#[crate_id = "timer"]; 2 | //#[crate_type = "lib"]; 3 | 4 | extern crate time; 5 | 6 | static SEC_MULTIPLIER:u64 = 1000 * 1000 * 1000; 7 | static MIN_MULTIPLIER:u64 = 60 * SEC_MULTIPLIER; 8 | static HR_MULTIPLIER:u64 = 60 * MIN_MULTIPLIER; 9 | 10 | pub struct Timer { 11 | start_time: u64, 12 | end_time: u64 13 | } 14 | 15 | impl Timer { 16 | pub fn new() -> Timer { 17 | Timer { start_time: 0, end_time: 0} 18 | } 19 | pub fn start(&mut self) -> () { 20 | self.start_time = time::precise_time_ns(); 21 | } 22 | pub fn end(&mut self) -> () { 23 | self.end_time = time::precise_time_ns(); 24 | } 25 | pub fn get_time_string(&self) -> StrBuf { 26 | return format_as_time(self.get_total_time()); 27 | } 28 | pub fn get_total_time(&self) -> u64 { 29 | return self.end_time - self.start_time; 30 | } 31 | pub fn show_time(&self) -> () { 32 | println!("Total time: {:s}", self.get_time_string()); 33 | } 34 | pub fn show_time_of(&self,txt:&str) -> () { 35 | println!("Total time:{:s}={:s}", txt,self.get_time_string()); 36 | } 37 | } 38 | 39 | /// automatically profile a scopeblock, RAII based. 40 | pub struct Profiler { 41 | time:Timer, 42 | name:StrBuf, 43 | } 44 | 45 | static mut g_depth:int=0; // TODO - use an appropriate primitive, threadsafe, howto? 46 | 47 | /// helper to automatically profile a scope block. place a "let p=Profiler::new("my_profiler")" at the begining of a scope, time is reported at the end using drop. Care would be needed if you were profiling other drops.. 48 | impl Profiler { 49 | // todo - cfg(profile).. 50 | pub fn new(n:&'static str)->Profiler{ 51 | let mut p=Profiler { time: Timer::new(), name:n.to_strbuf()}; 52 | p.time.start(); 53 | unsafe {g_depth+=1;}; 54 | p 55 | } 56 | } 57 | impl Drop for Profiler { 58 | fn drop(&mut self) { 59 | unsafe {g_depth-=1;}; 60 | self.time.end(); 61 | self.time.show_time_of(self.name.as_slice()); 62 | } 63 | } 64 | 65 | pub fn format_as_time(total_time: u64) -> StrBuf { 66 | let hours = total_time / HR_MULTIPLIER; 67 | let minutes = (total_time 68 | - hours * HR_MULTIPLIER) 69 | / MIN_MULTIPLIER; 70 | let seconds = (total_time 71 | - hours * HR_MULTIPLIER 72 | - minutes * MIN_MULTIPLIER) 73 | / SEC_MULTIPLIER; 74 | let nanoseconds = total_time 75 | - hours * HR_MULTIPLIER 76 | - minutes * MIN_MULTIPLIER 77 | - seconds * SEC_MULTIPLIER; 78 | 79 | let mut time_string = StrBuf::new(); 80 | if hours > 0 { 81 | time_string.push_str(format!("{}:", hours as int)); 82 | } 83 | if hours > 0 || minutes > 0 { 84 | if minutes < 10 && hours > 0 { 85 | time_string.push_str("0"); 86 | } 87 | time_string.push_str(format!("{}:", minutes as int)); 88 | } 89 | if hours > 0 || minutes > 0 || seconds > 0 { 90 | if seconds < 10 && (minutes > 0 || hours > 0) { 91 | // HACK: format!("%02?.", seconds) doesn't zero pad 92 | time_string.push_str("0"); 93 | } 94 | time_string.push_str(format!("{}.", seconds as int)); 95 | // nanoseconds don't need to be quite as accurate if we measure seconds 96 | let ns_as_string = format!("{:.5?}", (nanoseconds as f64) / (SEC_MULTIPLIER as f64)); 97 | time_string.push_str(format!("{:s}", ns_as_string.slice(2, 5))); 98 | } else { 99 | time_string.push_str(format!("{:s}", format_number(nanoseconds))); 100 | } 101 | 102 | if hours > 0 { 103 | time_string.push_str(" hr"); 104 | } else if minutes > 0 { 105 | time_string.push_str(" min"); 106 | } else if seconds > 0 { 107 | time_string.push_str(" sec"); 108 | } else { 109 | time_string.push_str(" ns"); 110 | } 111 | 112 | //time_string += format!(" ({})", total_time); 113 | 114 | return time_string.as_slice().to_strbuf(); 115 | } 116 | 117 | fn format_number(num: u64) -> StrBuf { 118 | let repr = num.to_str(); 119 | let mut ret_val = StrBuf::new(); 120 | let mut index = 0; 121 | let length = repr.len(); 122 | 123 | while index < length { 124 | ret_val.push_str(repr.slice(index, index + 1)); 125 | 126 | if (length - index - 1) % 3 == 0 && length > index + 1{ 127 | ret_val.push_str(","); 128 | } 129 | index += 1; 130 | } 131 | 132 | return ret_val.as_slice().to_strbuf() 133 | } 134 | 135 | #[test] 136 | fn format_number_test() { 137 | let num1 = 123456789; 138 | let num2 = 12345678; 139 | let num3 = 1234; 140 | 141 | assert!(format_number(num1) == "123,456,789"); 142 | assert!(format_number(num2) == "12,345,678"); 143 | assert!(format_number(num3) == "1,234"); 144 | } 145 | 146 | #[test] 147 | fn format_as_time_test() { 148 | let num1 = 2000; // ns 149 | let num2 = 3 * SEC_MULTIPLIER + 141591234; 150 | let num3 = 1 * MIN_MULTIPLIER + 5 * SEC_MULTIPLIER + 98765432; 151 | let num4 = 3 * HR_MULTIPLIER + num3; 152 | 153 | assert!(format_as_time(num1) == "2,000 ns"); 154 | assert!(format_as_time(num2) == "3.141 sec"); 155 | assert!(format_as_time(num3) == "1:05.098 min"); 156 | assert!(format_as_time(num4) == "3:01:05.098 hr"); 157 | } 158 | -------------------------------------------------------------------------------- /htmlwriter.rs: -------------------------------------------------------------------------------- 1 | use rf_common::*; 2 | use std::iter::range_inclusive; 3 | 4 | pub struct HtmlWriter { 5 | pub doc:StrBuf, 6 | pub tag_stack:Vec, // todo- these can be strslice? &str even? 7 | pub xlat:HashMap, // todo - remove this, just use a match to translate? 8 | } 9 | 10 | /// convert u8 into html char. 11 | fn mk_xlat_table()-> HashMap 12 | { 13 | let mut xlat= HashMap::new(); 14 | // let mut i=0u8; 15 | for i in range_inclusive(0u8, 255) { 16 | 17 | xlat.insert(i as char, 18 | match i as char{ 19 | ' ' =>" ".to_strbuf(), 20 | '<' =>"<".to_strbuf(), 21 | '>' =>">".to_strbuf(), 22 | '&' =>"&".to_strbuf(), 23 | '\t' =>"    ".to_strbuf(), 24 | c => StrBuf::from_char(1,c),//x.slice(0,1) 25 | }); 26 | } 27 | xlat 28 | } 29 | /// helper object for building html docs, puts tags in a stack for convinient close 30 | 31 | impl<'a> HtmlWriter { 32 | pub fn new()->HtmlWriter { HtmlWriter { doc:StrBuf::new(), tag_stack:Vec::new(), xlat:mk_xlat_table()}} 33 | 34 | pub fn write_quoted_str(&'a mut self, a:&str)->&'a mut HtmlWriter { 35 | self.doc.push_str("\""); 36 | self.doc.push_str(a); 37 | self.doc.push_str("\""); 38 | self 39 | } 40 | pub fn begin_tag_ext(&'a mut self, tag_name:&str, key_values:&[(StrBuf,StrBuf)])->&'a mut HtmlWriter { 41 | self.write_tag_sub(tag_name,key_values,false); 42 | self.tag_stack.push(tag_name.to_strbuf()); 43 | self 44 | } 45 | pub fn begin_tag(&'a mut self, tag_name:&str)->&'a mut HtmlWriter { 46 | self.begin_tag_ext(tag_name,&[]) 47 | } 48 | pub fn begin_tag_check(&'a mut self, tag_name:&str)->int { 49 | self.begin_tag_ext(tag_name,&[]); 50 | self.depth() 51 | } 52 | pub fn write_tag_ext(&'a mut self, tag_name:&str, key_values:&[(StrBuf,StrBuf)])->&'a mut HtmlWriter { 53 | self.write_tag_sub(tag_name,key_values,true) 54 | } 55 | pub fn write_tag(&'a mut self, tag_name:&str)->&'a mut HtmlWriter { 56 | self.write_tag_sub(tag_name,&[],true); 57 | self 58 | } 59 | fn write_tag_sub(&'a mut self, tag_name:&str, key_values:&[(StrBuf,StrBuf)], closed:bool)->&'a mut HtmlWriter { 60 | self.doc.push_str("<"+tag_name); 61 | for &(ref k,ref v) in key_values.iter() { 62 | self.doc.push_str(" "); 63 | self.doc.push_str(k.as_slice()); 64 | self.doc.push_str("="); 65 | self.write_quoted_str(v.as_slice()); 66 | } 67 | if closed { self.doc.push_str("/"); } 68 | self.doc.push_str(">"); 69 | self 70 | } 71 | pub fn end_tag(&'a mut self)->&'a mut HtmlWriter { 72 | match self.tag_stack.pop() { 73 | Some(tag_name) => { 74 | self.doc.push_str(""); 77 | }, 78 | None => () 79 | }; 80 | self 81 | } 82 | pub fn depth(&self)->int { self.tag_stack.len() as int } 83 | pub fn end_tag_check(&'a mut self,depth:int) { 84 | self.check_depth(depth); 85 | self.end_tag(); 86 | } 87 | #[allow(dead_code)] 88 | pub fn end_all_tags(&'a mut self)->&'a mut HtmlWriter { 89 | while self.tag_stack.len()>0 { 90 | self.end_tag(); 91 | } 92 | self 93 | } 94 | pub fn write(&'a mut self,t:&str)->&'a mut HtmlWriter { 95 | for x in t.chars() { 96 | self.doc.push_str(self.xlat.get(&x).as_slice()); 97 | }; 98 | self 99 | } 100 | // todo rename "write_raw?" 101 | #[allow(dead_code)] 102 | pub fn write_html(&'a mut self,t:&str)->&'a mut HtmlWriter { 103 | self.doc.push_str(t); 104 | self 105 | } 106 | pub fn write_tagged(&'a mut self, tagname:&str, text:&str)->&'a mut HtmlWriter { 107 | self.begin_tag(tagname).write(text).end_tag() 108 | } 109 | pub fn writeln_tagged(&'a mut self, tagname:&str, text:&str)->&'a mut HtmlWriter { 110 | self.begin_tag(tagname).write(text).end_tag().write_tag("br") 111 | } 112 | pub fn writeln(&'a mut self, text:&str)->&'a mut HtmlWriter { 113 | self.write(text).write_tag("br") 114 | } 115 | pub fn write_u8_(&'a mut self, x:u8)->&'a mut HtmlWriter { 116 | self.doc.push_str(self.xlat.get(&(x as char)).to_owned()); 117 | self 118 | } 119 | pub fn begin_tag_anchor(&'a mut self, anchor:&str)->&'a mut HtmlWriter { 120 | self.begin_tag_ext("a",&[(StrBuf::from_str("id"),StrBuf::from_str(anchor))]); 121 | self 122 | } 123 | pub fn begin_tag_link(&'a mut self, link:&str)->&'a mut HtmlWriter { 124 | self.begin_tag_ext("a",&[(StrBuf::from_str("href"),StrBuf::from_str(link))]); 125 | self 126 | } 127 | #[allow(dead_code)] 128 | pub fn write_space(&'a mut self)->&'a mut HtmlWriter { 129 | self.doc.push_str(" "); 130 | self 131 | } 132 | pub fn check_depth(&self,depth:int) { 133 | if self.depth() !=depth { 134 | fail!(format!("check_depth should be {} it is {}", depth, self.depth())) 135 | } 136 | } 137 | pub fn as_str<'s>(&'s self)->&'s str { 138 | return self.doc.as_slice(); 139 | } 140 | pub fn as_bytes<'s>(&'s self)->&'s[u8]{ 141 | return self.doc.as_bytes(); 142 | } 143 | } 144 | 145 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifndef RUST_PATH 2 | $(info Set $$RUST_PATH= to be able to link to rust std libs) 3 | $(error $$RUST_PATH is also required to generate HTML for the rust libs) 4 | RF_LIBS = 5 | else 6 | # RF_LIBS = -L $(RUST_PATH)/x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-gnu/lib 7 | endif 8 | ifndef RUST_LIBS 9 | $(info set RUST_LIBS to point to compiled libraries, ) 10 | $(info using /usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib by default ) 11 | RF_LIBS = -L /usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib 12 | else 13 | RF_LIBS = -L $(RUST_LIBS) 14 | endif 15 | 16 | RF_OPTS = $(RF_LIBS) -o html/ -C 17 | SRC=$(wildcard *.rs) 18 | RUST_FIND=$(shell pwd)/rustfind 19 | RUSTSRC=$(RUST_PATH)/src 20 | RUSTFLAGS = --opt-level=3 -A non-camel-case-types 21 | 22 | # generate HTML browser for the main sourcetree 23 | html: html_sub callgraph tags 24 | 25 | html_sub: rustfind 26 | ./rustfind rustfind.rs $(RF_OPTS) -x $(RUSTSRC) 27 | 28 | test_dump: rustfind 29 | ./rustfind -d $(RF_OPTS) test_input.rs 30 | 31 | #default behaviour, dump json map of spans.. 32 | test_json: rustfind 33 | ./rustfind -j $(RF_OPTS) test_input.rs 34 | interactive: rustfind 35 | ./rustfind -i $(RF_OPTS) test_input.rs 36 | 37 | #run this tool on test sources 38 | test1 : rustfind 39 | ./rustfind test_input.rs -j $(RF_LIBS) -o html/ 40 | ./rustfind test_input.rs $(RF_OPTS) 41 | #firefox html/test_input.rs.html 42 | 43 | test0 : rustfind 44 | ./rustfind test_input0.rs -j -x $(RUSTSRC) $(RF_OPTS) 45 | ./rustfind test_input0.rs -w -x $(RUSTSRC) $(RF_OPTS) 46 | firefox html/test_input0.rs.html 47 | 48 | #make emacs ctags for this project, 49 | tags: 50 | echo $(RUSTSRC) 51 | ctags -e -f TAGS.emacs --options=$(RUSTSRC)/etc/ctags.rust -R . 52 | 53 | callgraph : html_sub 54 | neato -Tcmap html/callgraph.dot -o html/callgraph_cmap.html 55 | neato -Tpng html/callgraph.dot -o html/callgraph.png 56 | fdp -Tpng html/callgraph.dot -o html/callgraph2.png 57 | cat resources/callgraph_header.html html/callgraph_cmap.html resources/callgraph_footer.html > html/callgraph.html 58 | 59 | # Make the HTML view of the main rust sourcetree 60 | ifdef RUST_PATH 61 | -include $(RUST_PATH)/mk/crates.mk 62 | else 63 | CRATES := 64 | endif 65 | 66 | define RUST_TARGET_LIB 67 | rust_lib$(1): rustfind rust_lib_pre $$(patsubst %,rust_lib%,$$(filter-out native:%,$$(DEPS_$(1)))) 68 | @echo "Generating HTML for lib$(1)" 69 | @export CFG_VERSION=0; export CFG_PREFIX=0;export CFG_RUSTLIBDIR=0;export CF_COMPILER=0;export CG_LIBDIR_RELATIVE=0; \ 70 | $(RUSTFIND) $(RUSTSRC)/lib$(1)/lib.rs $(RF_LIBS) -o $(RUSTSRC)/html -x $(RUSTSRC) 71 | rust_lib$(1)_nodeps: rustfind rust_lib_pre 72 | @echo "Generating HTML for lib$(1)" 73 | @export CFG_VERSION=0; export CFG_PREFIX=0;export CFG_RUSTLIBDIR=0;export CF_COMPILER=0;export CG_LIBDIR_RELATIVE=0; \ 74 | $(RUSTFIND) $(RUSTSRC)/lib$(1)/lib.rs $(RF_LIBS) -o $(RUSTSRC)/html -x $(RUSTSRC) 75 | endef 76 | 77 | $(foreach crate,$(CRATES),$(eval $(call RUST_TARGET_LIB,$(crate)))) 78 | 79 | rust_src: rustfind rust_lib_pre $(patsubst %,rust_lib%,$(filter-out native:%,$(CRATES))) 80 | 81 | rust_lib_pre: rustfind 82 | @echo "========================================================================" 83 | @echo "= Generating HTML for main rust sourcetree =" 84 | @echo "= Be patient, sorry this is unoptimized and will take a very long time =" 85 | @echo "========================================================================" 86 | @echo $(CRATES) 87 | 88 | # compile the main rust sourcetree html, (compiler plus libraries) 89 | # brute force because the above wasn't working, we have extra extra options for rustc aswell. 90 | # any suggestions on how to make the makefile better welcome. 91 | # 'rust_src:' is a smarter target to do the same thing, but i couldn't get it to work 92 | rust: rust_lib_pre 93 | @if [ ! -f /usr/local/bin/rustfind ];then echo "run make install first"; /usr/local/bin/rustfind; fi ; 94 | 95 | cd $(RUST_PATH)/src;pwd; 96 | 97 | cd $(RUST_PATH)/src;pwd; rustfind libcore/lib.rs 98 | cd $(RUST_PATH)/src;pwd; rustfind libstd/lib.rs 99 | cd $(RUST_PATH)/src;pwd; rustfind libgreen/lib.rs 100 | cd $(RUST_PATH)/src;pwd; rustfind librustuv/lib.rs 101 | cd $(RUST_PATH)/src;pwd; rustfind libnative/lib.rs 102 | cd $(RUST_PATH)/src;pwd; rustfind liblibc/lib.rs 103 | cd $(RUST_PATH)/src;pwd; rustfind libflate/lib.rs 104 | cd $(RUST_PATH)/src;pwd; rustfind libarena/lib.rs 105 | cd $(RUST_PATH)/src;pwd; rustfind libglob/lib.rs 106 | cd $(RUST_PATH)/src;pwd; rustfind libterm/lib.rs 107 | cd $(RUST_PATH)/src;pwd; rustfind libsemver/lib.rs 108 | cd $(RUST_PATH)/src;pwd; rustfind libuuid/lib.rs 109 | cd $(RUST_PATH)/src;pwd; rustfind libserialize/lib.rs 110 | cd $(RUST_PATH)/src;pwd; rustfind libsync/lib.rs 111 | cd $(RUST_PATH)/src;pwd; rustfind libgetopts/lib.rs 112 | 113 | cd $(RUST_PATH)/src;pwd; rustfind libcollections/lib.rs 114 | cd $(RUST_PATH)/src;pwd; rustfind libnum/lib.rs 115 | cd $(RUST_PATH)/src;pwd; rustfind libtest/lib.rs 116 | cd $(RUST_PATH)/src;pwd; rustfind librand/lib.rs 117 | cd $(RUST_PATH)/src;pwd; rustfind libworkcache/lib.rs 118 | # cd $(RUST_PATH)/src;pwd; ~/rustfind/rustfind libextra/lib.rs 119 | cd $(RUST_PATH)/src;pwd; rustfind liburl/lib.rs 120 | cd $(RUST_PATH)/src;pwd; rustfind liblog/lib.rs 121 | 122 | cd $(RUST_PATH)/src;pwd; rustfind libsyntax/lib.rs 123 | export CFG_VERSION=0;export CFG_COMPILER=0;export CFG_PREFIX=0;export CFG_LIBDIR_RELATIVE=0; export CFG_RUSTLIBDIR=0;export CFG_COMPILER_TRIPLE=0;cd $(RUST_SRC);pwd; ~/rustfind/rustfind librustc/lib.rs 124 | cd $(RUST_PATH)/src;pwd; rustfind librustdoc/lib.rs 125 | 126 | cd $(RUST_PATH)/src;pwd; rustfind libfourcc/lib.rs 127 | cd $(RUST_PATH)/src;pwd; rustfind libhexfloat/lib.rs 128 | cd $(RUST_PATH)/src;pwd; rustfind libgraphviz/lib.rs 129 | cd $(RUST_PATH)/src;pwd; rustfind libtime/lib.rs 130 | 131 | help: 132 | @echo "rustfind makefile:" 133 | @echo " " 134 | @echo "make rustfind - compile the rustfind tool" 135 | @echo "make install - copy to /usr/local/bin" 136 | @echo "make rust - run rustfind on the main rust sourcetree" 137 | @echo "make html - run rustfind on its own sourcetree" 138 | @echo " " 139 | @echo "once compiled, you can invoke 'rustfind ' to build linked htmlview" 140 | @echo "but its more useful if you build the main rust sourcetree first for reference" 141 | 142 | #Compile the main executable 143 | 144 | rustfind: rustfind.rs $(SRC) 145 | rustc $(RUSTFLAGS) rustfind.rs 146 | 147 | install :rustfind 148 | cp ./rustfind /usr/local/bin 149 | 150 | clean: 151 | rm -f rustfind 152 | rm -f *.html 153 | rm -f *.*~ 154 | rm -f html/*.html 155 | -------------------------------------------------------------------------------- /ioutil.rs: -------------------------------------------------------------------------------- 1 | #![macro_escape] 2 | 3 | use std::io::{File, UserDir}; 4 | use std::io::fs::{mkdir_recursive,copy,walk_dir}; 5 | use std::cast; 6 | pub use std::io::{stdout, stdin}; 7 | pub use libc::{fwrite, fread, fseek, fopen, ftell, fclose, FILE, c_void, c_char, SEEK_END, 8 | SEEK_SET}; 9 | pub use std::mem::size_of; // for size_of 10 | pub use std::num::Zero; 11 | use std::io::{BufferedReader, IoResult}; 12 | use std::vec::Vec; 13 | use std::vec; 14 | 15 | pub type Size_t=u64; // todo - we're not sure this should be u64 16 | // as the libc stuff seems to want. 17 | // should it be uint? 18 | 19 | // TODO cleanup, we can just use the mature rust fileio now. 20 | 21 | macro_rules! logi{ 22 | ($($a:expr),*)=>(println!("{}", file!()+":"+line!().to_str()+": " $(+$a.to_str())* )) 23 | } 24 | //macro_rules! dump{ ($a:expr)=>(logi!(fmt!("%s=%?",stringify!($a),$a).indent(2,160));)} 25 | /*fn newline_if_over(a:StrBuf,l:uint) -> StrBuf { 26 | if a.len()>l { 27 | a+"\n" 28 | } else { 29 | a 30 | } 31 | }*/ 32 | macro_rules! dump{ ($($a:expr),*)=> 33 | ( { let mut txt=StrBuf::new(); 34 | $( txt=txt.append( 35 | format!("{:s}={:?}",stringify!($a),$a) + ",") 36 | );*; 37 | logi!(txt); 38 | } 39 | ) 40 | } 41 | 42 | 43 | macro_rules! trace{ 44 | ()=>( 45 | println!("{}", file!().to_str()+":"+line!().to_str()+": "); 46 | ); 47 | } 48 | 49 | pub trait Dbprint {fn dbprint(&self);} 50 | 51 | pub trait EndianSwap { 52 | fn endian_swap(&self)->Self; 53 | } 54 | 55 | // dbprint postfix form means we can print tuples? 56 | impl Dbprint for T { 57 | fn dbprint(&self) { 58 | println!("{}", self.to_str()); 59 | } 60 | } 61 | 62 | pub fn promptInput(prompt:&str)->StrBuf { 63 | println!("{}", prompt); 64 | StrBuf::from_str(BufferedReader::new(stdin()).read_line().unwrap()) // TODO add error handling 65 | } 66 | 67 | pub fn as_void_ptr(a:&T)->*c_void { unsafe {cast::transmute(a) } } 68 | pub fn as_mut_void_ptr(a:&T)->*mut c_void {unsafe { cast::transmute(a) } } 69 | 70 | // this doest work? 71 | pub trait VoidPtr { 72 | fn as_void_ptr(&self)->*c_void; 73 | fn as_mut_void_ptr(&self)->*mut c_void; 74 | } 75 | impl VoidPtr for T { 76 | fn as_void_ptr(&self)->*c_void {unsafe { cast::transmute(self) } } 77 | fn as_mut_void_ptr(&self)->*mut c_void {unsafe { cast::transmute(self) } } 78 | } 79 | 80 | pub fn printStr(a:&T){println!("{}", a.to_str());} 81 | 82 | pub fn c_str(rustStr:&str)->*c_char { 83 | unsafe { 84 | // as_c_str(rustStr,|x|x) 85 | rustStr.to_c_str().unwrap() 86 | } 87 | } 88 | 89 | 90 | pub unsafe fn fileOpen(filename:&str,mode:&str)-> *FILE { 91 | fopen(c_str(filename),c_str(mode)) 92 | } 93 | 94 | pub fn file_create_with_dirs(file_path: &Path) -> IoResult { 95 | use std::io::{File, UserDir}; 96 | use std::io::fs::mkdir_recursive; 97 | 98 | mkdir_recursive(&file_path.dir_path(), UserDir).and_then(|()| { 99 | File::create(file_path) 100 | }).map_err(|e| { 101 | println!("error: could not write to {} - {}", file_path.display(), e); 102 | e 103 | }) 104 | } 105 | 106 | /* 107 | pub fn fileLoadArray(filename:&str)->~[T] { 108 | unsafe { 109 | let fp=fopen(c_str_from(filename),as_c_str("rb",|x|x)); 110 | } 111 | } 112 | */ 113 | 114 | 115 | pub unsafe fn fileWrite(fp:*FILE, array:&[T]) { 116 | printStr(&sizeofArray(array)); 117 | fwrite(as_void_ptr(&array[0]),sizeofArray(array),1,fp); 118 | } 119 | 120 | 121 | pub unsafe fn fileWriteStruct(fp:*FILE, s:&T) { 122 | fwrite(as_void_ptr(s),size_of::() as Size_t,1,fp); 123 | } 124 | 125 | 126 | pub unsafe fn fileRead(fp:*FILE,numElems:Size_t)->Vec { 127 | let buffer=Vec::from_elem(numElems as uint, Zero::zero()); 128 | fread(as_mut_void_ptr(&buffer.get(0)),numElems,size_of::() as Size_t,fp); 129 | buffer 130 | } 131 | 132 | 133 | pub unsafe fn fileReadBytes(fp:*FILE,numBytes:Size_t)->Vec { 134 | // todo - simply express as the above.. 135 | let buffer=Vec::from_elem(numBytes as uint,0 as u8); 136 | fread(as_mut_void_ptr(buffer.get(0)),numBytes,1,fp); 137 | buffer 138 | } 139 | 140 | 141 | pub unsafe fn fileSize(fp:*FILE)->Size_t { 142 | fseek(fp,0,SEEK_END); 143 | let pos=ftell(fp); 144 | fseek(fp,0,SEEK_SET); 145 | pos as Size_t 146 | } 147 | 148 | 149 | pub fn fileLoad(filename:&str)->Vec { 150 | unsafe { 151 | // TODO - should do with patter match null, fp? 152 | let fp= fileOpen(filename,"rb"); 153 | if fp==0 as *FILE { 154 | printStr(&("could not read "+filename)); 155 | Vec::new() 156 | } 157 | else 158 | { 159 | let buffer=fileReadBytes(fp,fileSize(fp)); 160 | fclose(fp); 161 | buffer 162 | } 163 | } 164 | } 165 | 166 | 167 | pub unsafe fn fileWriteRange(fp:*FILE, array:&[T],start:uint,end:uint) { 168 | printStr(&sizeofArray(array)); 169 | fwrite(as_void_ptr(&array[start]),sizeofArrayElem(array)*(end-start) as Size_t,1,fp); 170 | } 171 | 172 | pub fn sizeofArray(a:&[T])->Size_t { (size_of::() * a.len()) as Size_t } 173 | pub fn sizeofArrayElem(_:&[T])->Size_t { size_of::() as Size_t } 174 | 175 | 176 | pub fn fileSaveArray(buffer:&[T],filename:&str) { 177 | unsafe { 178 | let fp=fileOpen(filename,"wb"); 179 | if fp!=(0 as *FILE) { 180 | fileWrite(fp,buffer); 181 | //fwrite(to_void_ptr(&buffer[0]),sizeofArray(buffer),1,fp); 182 | fclose(fp); 183 | } else { 184 | printStr(&("could not write "+filename)); 185 | } 186 | } 187 | } 188 | 189 | 190 | pub fn fileSaveStr(text:&str, file_path: &Path) { 191 | let res = mkdir_recursive(&file_path.dir_path(), UserDir).and_then(|()| { 192 | let mut file = File::create(file_path); 193 | file.write_str(text) 194 | }); 195 | match res { 196 | Ok(()) => (), 197 | Err(e) => println!("error: could not write to {} - {}", file_path.display(), e) 198 | }; 199 | } 200 | 201 | pub fn copy_folder(source_dir: &Path, dest_dir: &Path)->Result<(),()> { 202 | let directories = walk_dir(source_dir); 203 | let res = match directories { 204 | Ok(mut directories) => { 205 | let mut result = Ok(()); 206 | for file in directories { 207 | let mut dest_path = Path::new(dest_dir); 208 | for c in file.components().skip(1) { 209 | dest_path.push(c); 210 | } 211 | let res = if file.is_dir () { 212 | mkdir_recursive(&dest_path, UserDir) 213 | } else { 214 | copy(&file, &dest_path) 215 | }; 216 | match res { 217 | Err(e) => { 218 | result = Err(e); 219 | break; 220 | }, 221 | _ => () 222 | } 223 | }; 224 | result 225 | }, 226 | Err(e) => { 227 | println!("Unable to copy directory `{}`: {}", source_dir.display(), e); 228 | return Err(()); 229 | } 230 | }; 231 | match res { 232 | Err(e) => {println!("Error while copying: {}", e)return Err(()) }, 233 | _ => return Ok(()) 234 | } 235 | } 236 | 237 | pub trait ResultUtil { 238 | fn expect(self, error_message: &'static str) -> T; 239 | } 240 | 241 | impl ResultUtil for Result { 242 | fn expect(self, error_message: &'static str) -> T { 243 | match self { 244 | Ok(res) => res, 245 | Err(_) => fail!(error_message) 246 | } 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /scripts/gtksourceview-3.0/styles/codedark.xml: -------------------------------------------------------------------------------- 1 | 2 | 24 | 25 | 26 | 27 | Paolo Borelli 28 | <_description>dark scheme derived from oblivion with extra defs 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 |