# # patch "git.ml" # from [2d5174877cd92be4f90003777cb2cabd2f243047] # to [d46a4993e5167aea7e5a1d5e2bee71f7f00ae859] # # patch "main.ml" # from [f26ef48aa5ed050e2c8876afa3937dfadd7b0dd7] # to [0ff0e7377579201a776760f2ecff06dc8879035c] # # patch "unidiff.ml" # from [27d78ed2191d1fb186ad09637874b4832c59b480] # to [fe18aec530b716b4d80c29b1730bdddb904bde36] # # patch "view.ml" # from [8eedf028bdba7f8651a52f74647f88cd6bd75bac] # to [feb6b7faf666d8dc16506d203149f970f08140d8] # # patch "view.mli" # from [8cf21ebc1a553dbec23d160331a7eced392f7210] # to [20aca504f554aa261079f762d6238447a0ee98e6] # # patch "viz_style.ml" # from [0765e6a24c5c364c7e44b4e50b9b2620b60668d6] # to [41467004749f0b4db18d853b48b12a5499733060] # --- git.ml +++ git.ml @@ -22,7 +22,51 @@ } +let fetch_history base id = + log "exec" "### exec: Running rev-tree %s'" id ; + match Gspawn.sync + ~working_directory:base + ~flags:[`SEARCH_PATH] + ["rev-tree"; id] with + | Gspawn.EXITSTATUS 0, stdout, _ -> + stdout + | _, _, stderr -> + Viz_types.errorf "rev-tree invocation failed: '%s'" stderr + +let scan_history data = + let get_id s = + match string_split ~max_elem:2 ':' s with + | id :: _ -> id + | _ -> raise Not_found in + + let rec proc ag i = + if i >= String.length data + then ag + else begin + let j = String.index_from data i '\n' in + let l = String.sub data i (j - i) in + let ag = + match string_split ' ' l with + | _ :: node :: parents -> + let id = get_id node in + let parents = List.map get_id parents in + let node = { id = id ; + kind = if List.length parents > 1 then MERGE else REGULAR ; + family = List.map (fun i -> i, PARENT) parents } in + let edges = + List.fold_left + (fun e p -> EdgeMap.add (p, id) SAME_BRANCH e) + ag.ancestry parents in + { ag with + nodes = NodeMap.add id node ag.nodes ; + ancestry = edges } + | _ -> ag in + proc ag (j+1) + end in + + proc Viz_types.empty_agraph 0 + let fetch_commit_object base id = log "exec" "### exec: Running 'cat-file commit %s'" id ; match Gspawn.sync @@ -118,14 +162,15 @@ | _ -> failwith "Could not parse changeset" -let scan_change = function `LINUS -> scan_change_linus | `PASKY -> scan_change_pasky - let get_changes k base id1 id2 = + let (sep, scan_fun) = + match k with + | `LINUS -> '\000', scan_change_linus + | `PASKY -> '\n', scan_change_pasky in List.fold_left - (fun acc l -> try scan_change k l :: acc with Failure _ -> - Printf.eprintf "parse failure for '%s'\n%!" l ; acc) + (fun acc l -> scan_fun l :: acc) [] - (string_split '\000' (fetch_changeset base id1 id2)) + (string_split sep (fetch_changeset base id1 id2)) let get_changeset k base get_commit id = let c = get_commit id in @@ -145,7 +190,9 @@ let d, kind = if Sys.file_exists ds then ds, `PASKY else if Sys.file_exists dl then dl, `LINUS else failwith "unknown" in - let head = with_file_in input_channel (Filename.concat d "HEAD") in + let head = + string_slice ~e:(-1) + (with_file_in input_channel (Filename.concat d "HEAD")) in let get_commit = Viz_misc.make_cache (get_commit_object db_name) in let get_changeset = Viz_misc.make_cache (get_changeset kind db_name get_commit) in { base = db_name ; @@ -163,21 +210,7 @@ let fetch_branches d = [] let fetch_ancestry_graph d _ = - let rec proc ag id = - if NodeMap.mem id ag.nodes - then ag - else begin - let c = d.get_commit id in - let node = { id = id ; - kind = if List.length c.parents > 1 then MERGE else REGULAR ; - family = List.map (fun i -> i, PARENT) c.parents } in - let n_ag = - { ag with nodes = NodeMap.add id node ag.nodes ; - ancestry = List.fold_left (fun e p -> EdgeMap.add (p, id) SAME_BRANCH e) ag.ancestry c.parents } in - List.fold_left proc n_ag c.parents - end in - proc Viz_types.empty_agraph d.head - + scan_history (fetch_history d.base d.head) let fetch_revision d id = { revision_id = id ; --- main.ml +++ main.ml @@ -1,10 +1,5 @@ open Viz_misc -type mt_options = - | MTopt_none - | MTopt_db of string - | MTopt_full of string * string - let unquote s = if s.[0] = '"' then @@ -14,39 +9,20 @@ (Lexing.from_string (String.sub s 1 (len - 1))) else s -let parse_MT_options () = - let mt_options = Filename.concat "MT" "options" in - match try with_file_in input_lines mt_options with Sys_error _ -> [] with - | [] -> MTopt_none - | lines -> - let options = - try - List.fold_right - (fun s acc -> - match string_split ~max_elem:2 ' ' s with - | [a; b] -> (a, unquote b) :: acc - | _ -> acc) - lines [] - with Failure _ -> [] in - match may_assoc "database" options with - | None -> MTopt_none - | Some db -> - match may_assoc "branch" options with - | None -> MTopt_db db - | Some branch -> MTopt_full (db, branch) - let parse_options args = match args with - | db :: [] | db :: "" :: _ -> MTopt_db db - | db :: branch :: _ -> MTopt_full (db, branch) - | [] -> parse_MT_options () + | db :: _ -> Some db + | [] -> + if Sys.file_exists ".dircache" || Sys.file_exists ".git" + then Some "." + else None let parse_cli () = let anons = ref Q.empty in let aa = ref true in let cli_args = [ "-noaa", Arg.Clear aa, "don't use an anti-aliased canvas" ] in let usg_msg = - Printf.sprintf "usage: %s [options] [db [branch]]" + Printf.sprintf "usage: %s [options] [git-controlled directory]" (Filename.basename Sys.executable_name) in Arg.parse cli_args (fun a -> anons := Q.push !anons a) usg_msg ; (!aa, parse_options (Q.to_list !anons)) @@ -78,11 +54,9 @@ begin try match mt_options with - | MTopt_none -> () - | MTopt_db fname -> + | None -> () + | Some fname -> View.open_db v fname None - | MTopt_full (fname, branch) -> - View.open_db v fname (Some branch) with Viz_types.Error msg -> View.error_notice ~parent:w msg end ; --- unidiff.ml +++ unidiff.ml @@ -43,11 +43,15 @@ Q.list_fold (fun q (n, s, len) -> if is_prefix "--- " text s + then Q.push q (HEADER n) + else if is_prefix "+++ " text s then begin - let filename = String.sub text (s + 4) (len - 4) in - Q.push_list q [ HEADER n ; FILE (filename, n) ] end - else if is_prefix "+++ " text s - then Q.push q (HEADER n) + let filename = + let re = Str.regexp "[0-9a-f]+/\\(.*\\) (" in + if Str.string_match re text (s + 4) + then Str.matched_group 1 text + else String.sub text (s + 4) (len - 4) in + Q.push_list q [ HEADER n ; FILE (filename, n - 1) ] end else if is_prefix "@@ " text s then Q.push q (HUNK n) else if is_prefix "-" text s --- view.ml +++ view.ml @@ -50,13 +50,7 @@ cert_view : GTree.view ; } -type branch_selector = { - combo : GEdit.combo_box GEdit.text_combo ; - mutable combo_signal : GtkSignal.id option ; - sub : GButton.toggle_button ; - mutable branches : string array ; - select_signal : Viz_types.query Signal.t ; - } +type branch_selector = unit type event = [ `CLEAR @@ -322,102 +316,14 @@ module Branch_selector = struct - let select_branch s = - let (combo, _) = s.combo in - try - Signal.emit s.select_signal - begin - match combo#active with - | -1 -> raise Exit - | 0 -> ALL - | i -> - let b = s.branches.(i - 1) in - if s.sub#active then COLLECTION b else BRANCH b - end - with Exit -> () - - let with_inactive_combo ({ combo = (combo, _) } as s) f = - let id = some s.combo_signal in - GtkSignal.handler_block combo#as_widget id ; - f s.combo ; - GtkSignal.handler_unblock combo#as_widget id - let make ~packing = let hb = GPack.hbox ~border_width:4 ~packing () in - let combo = - ignore (GMisc.label ~text:"Branch: " ~packing:hb#pack ()) ; - let (model, column) as store = GTree.store_of_list Gobject.Data.string [] in - let combo = GEdit.combo_box ~model ~packing:hb#pack () in - let r = GTree.cell_renderer_text [] in - combo#pack r ; - combo#add_attribute r "markup" column ; - (combo, store) in - let checkb = - GButton.check_button - ~label:"Include sub-branches" - ~active:false ~packing:hb#pack () in let entry = GEdit.entry ~packing:(hb#pack ~from:`END) () in - begin - let tooltips = GData.tooltips () in - tooltips#set_tip - ~text:"Find a node by its revision id, tag or date (YYYY-MM-DD)" - entry#coerce - end ; let lbl = GMisc.label ~text:"Find:" ~packing:(hb#pack ~from:`END) () in - let c = - { combo = combo ; combo_signal = None ; - sub = checkb ; branches = [||] ; - select_signal = Signal.make () } in - begin - let callback () = select_branch c in - let (combo, _) = combo in - c.combo_signal <- Some (combo#connect#changed ~callback) ; - ignore (checkb#connect#toggled ~callback) - end ; let f = { last_find = "", [] ; find_signal = Signal.make () ; find_entry = entry } in ignore (entry#connect#activate (fun () -> Signal.emit f.find_signal entry#text)) ; - (c, f) - - let connect v f = - Signal.connect v.selector.select_signal f - - let get_display_sub_branches v = v.selector.sub#active - - let clear { selector = s } = - s.branches <- [||] ; - with_inactive_combo s - (fun (_, (model, _)) -> model#clear ()) - - let populate { selector = s } br = - with_inactive_combo s - (fun (combo, (model, column)) -> - s.branches <- Array.of_list br ; - begin - let row = model#append () in - model#set ~row ~column "Everything" - end ; - List.iter - (fun b -> - let row = model#append () in - model#set ~row ~column (Glib.Markup.escape_text (utf8ize b))) - br) - - let set_branch { selector = s } b = - let (combo, _) = s.combo in - combo#set_active - begin - try 1 + array_index s.branches b - with Not_found -> - error_notice_f ~parent:s.sub "Could not find the branch '%s'" b ; - -1 - end - - let get_branch { selector = s } = - let (combo, _) = s.combo in - match combo#active with - | i when i > 0 -> Some s.branches.(i - 1) - | _ -> None + ((), f) end @@ -967,14 +873,10 @@ status_reporter = lazy (Status.new_reporter "monotone") } in - Branch_selector.connect v (handle_query v) ; - connect_event v (function | `NODE_SELECT id -> Canvas.display_selection_marker v id ; Info_Display.fetch_and_display_data v id - | `NODE_SWITCH_BRANCH branch -> - Branch_selector.set_branch v branch | `CLEAR -> Info_Display.clear_info v ; KeyNav.clear v ; @@ -988,7 +890,6 @@ let close v = - Branch_selector.clear v ; may Agraph.abort_layout v.agraph ; Canvas.clear v ; v.agraph <- None ; @@ -1002,12 +903,12 @@ let open_db v fname branch = + assert (branch = None) ; close v ; try let db = Database.open_db fname in v.db <- Some db ; - Branch_selector.populate v (Database.fetch_branches db) ; - may (Branch_selector.set_branch v) branch ; + handle_query v ALL ; Signal.emit v.event_signal `OPEN_DB with Viz_types.Error msg -> error_notice ~parent:v.canvas.w msg @@ -1015,9 +916,8 @@ let reload v = may (fun db -> - let branch = Branch_selector.get_branch v in let fname = Database.get_filename db in - open_db v fname branch) + open_db v fname None) v.db @@ -1065,12 +965,15 @@ v.prefs <- { v.prefs with style = p.style } ; need_redraw := true end ; - if !need_layout || !need_redraw - then Canvas.clear v ; - if !need_layout - then handle_query v (Agraph.get_query (some v.agraph)) - else if !need_redraw - then Canvas.update_graph v + if v.agraph <> None + then begin + if !need_layout || !need_redraw + then Canvas.clear v ; + if !need_layout + then handle_query v (Agraph.get_query (some v.agraph)) + else if !need_redraw + then Canvas.update_graph v + end let get_ancestors v id = Agraph.get_ancestors (some v.agraph) id --- view.mli +++ view.mli @@ -38,12 +38,6 @@ module Branch_selector : sig val make : packing:(GObj.widget -> unit) -> branch_selector * find - val connect : t -> (Viz_types.query -> unit) -> unit - val get_display_sub_branches : t -> bool - val clear : t -> unit - val populate : t -> string list -> unit - val set_branch : t -> string -> unit - val get_branch : t -> string option end module KeyNav : --- viz_style.ml +++ viz_style.ml @@ -240,7 +240,7 @@ let defaults = { font = "Monospace 8" ; - autocolor = BY_KEYID ; + autocolor = NONE ; lr_layout = false ; monotone_path = "monotone" ; style = [] ;