terminal user interface to jujutsu. Focused on speed and clarity
9
fork

Configure Feed

Select the types of activity you want to include in your feed.

support very very long files in view

+87 -29
+87 -29
jj_tui/bin/show_view.ml
··· 2 2 open Picos_std_structured 3 3 open Jj_tui.Logging 4 4 5 + type detail_state = 6 + | Loading 7 + | Loaded of Notty.image 8 + | Failed 9 + 5 10 type status_state = 6 11 | File_preview of (string * string) (*revision,filepath*) 7 12 | Graph_preview of string (*revision*) ··· 28 33 open Global_vars 29 34 open Jj_tui 30 35 31 - let viewState = Lwd.var I.empty 36 + type view_state = { 37 + summary : Notty.image 38 + ; detail : detail_state 39 + } 32 40 33 - let render_file_preview (rev, file) = 34 - (* we yield a bunch here to provide places for the computation to be terminated*) 35 - if file != "" 36 - then ( 37 - let log = jj_no_log [ "diff"; "-r"; rev; file ] in 41 + let viewState = Lwd.var { summary = I.empty; detail = Loading } 42 + 43 + let render_summary = function 44 + | File_preview (rev, file) -> 45 + let command = 46 + if file != "" 47 + then [ "diff"; "--summary"; "-r"; rev; file ] 48 + else [ "show"; "--summary"; "-r"; rev ] 49 + in 50 + let log = jj_no_log command in 38 51 Control.yield (); 39 52 let res = log |> AnsiReverse.colored_string in 40 53 Control.yield (); 41 - res) 42 - else I.string A.empty "" 54 + res 55 + | Graph_preview rev -> 56 + let log = jj_no_log ~snapshot:false [ "show"; "--summary"; "-r"; rev ] in 57 + Control.yield (); 58 + let res = log |> AnsiReverse.colored_string in 59 + Control.yield (); 60 + res 43 61 ;; 44 62 45 - let render_graph_preview rev = 46 - let log = jj_no_log ~snapshot:false [ "show"; "-s"; "--color-words"; "-r"; rev ] in 47 - Control.yield (); 48 - let res = log |> AnsiReverse.colored_string in 49 - Control.yield (); 50 - res 63 + let render_detail = function 64 + | File_preview (rev, file) -> 65 + let command = 66 + if file != "" then [ "diff"; "-r"; rev; file ] else [ "show"; "-r"; rev ] 67 + in 68 + let log = jj_no_log command in 69 + Control.yield (); 70 + let res = log |> AnsiReverse.colored_string in 71 + Control.yield (); 72 + res 73 + | Graph_preview rev -> 74 + let log = jj_no_log ~snapshot:false [ "diff"; "--color-words"; "-r"; rev ] in 75 + Control.yield (); 76 + let res = log |> AnsiReverse.colored_string in 77 + Control.yield (); 78 + res 51 79 ;; 52 80 53 81 (* Wait for messages to come in the stream. ··· 55 83 If a new message comes, we cancel the current computation and then start the new rendering 56 84 *) 57 85 let render_loop stream = 58 - let current_computation = ref (Promise.of_value ()) in 86 + let current_summary_computation = ref (Promise.of_value ()) in 87 + let current_detail_computation = ref (Promise.of_value ()) in 88 + let current_loading_computation = ref (Promise.of_value ()) in 59 89 let cursor = ref (Stream.tap stream) in 60 90 while true do 61 91 let msg, new_cursor = !cursor |> Stream.read in 62 92 cursor := new_cursor; 63 - Promise.terminate_after ~seconds:0. !current_computation; 64 - current_computation 93 + Promise.terminate_after ~seconds:0. !current_summary_computation; 94 + Promise.terminate_after ~seconds:0. !current_detail_computation; 95 + Promise.terminate_after ~seconds:0. !current_loading_computation; 96 + current_summary_computation 65 97 := Flock.fork_as_promise (fun () -> 66 98 try 67 - [%log debug "Rendering status view with: %a" pp_status_state msg]; 68 - viewState 69 - $= 70 - match msg with 71 - | File_preview (rev, file) -> 72 - render_file_preview (rev, file) 73 - | Graph_preview rev -> 74 - render_graph_preview rev 99 + [%log debug "Rendering status summary with: %a" pp_status_state msg]; 100 + let summary = render_summary msg in 101 + viewState $= { (Lwd.peek viewState) with summary } 75 102 with 76 103 | _ -> 77 104 [%log 78 105 warn 79 - "preview render failed. If this happens once it's probably just because \ 80 - a node was deleted. If it keeps happening and the user can't see anything, obviously this is important"]) 106 + "summary render failed. If this happens once it's probably just because \ 107 + a node was deleted. If it keeps happening and the user can't see \ 108 + anything, obviously this is important"]); 109 + current_loading_computation 110 + := Flock.fork_as_promise (fun () -> 111 + (* If it's been more than half a second, show the state as loading*) 112 + Control.sleep ~seconds:0.3; 113 + viewState $= { (Lwd.peek viewState) with detail = Loading }); 114 + current_detail_computation 115 + := Flock.fork_as_promise (fun () -> 116 + try 117 + [%log debug "Rendering status detail with: %a" pp_status_state msg]; 118 + let detail = Loaded (render_detail msg) in 119 + (*Make sure the loading is done*) 120 + !current_loading_computation |> Promise.terminate; 121 + viewState $= { (Lwd.peek viewState) with detail } 122 + with 123 + | _ -> 124 + [%log 125 + warn 126 + "detail render failed. If this happens once it's probably just because \ 127 + a node was deleted. If it keeps happening and the user can't see \ 128 + anything, obviously this is important"]; 129 + viewState $= { (Lwd.peek viewState) with detail = Failed }) 81 130 done 82 131 ;; 83 132 84 133 let render focus = 85 134 Flock.fork (fun () -> render_loop statusStream); 86 - Lwd.get viewState |>$ fun x -> 87 - x 135 + Lwd.get viewState |>$ fun { summary; detail } -> 136 + let detail_view = 137 + match detail with 138 + | Loading -> 139 + I.string A.empty "Loading..." 140 + | Loaded image -> 141 + image 142 + | Failed -> 143 + I.string A.empty "Failed to load diff" 144 + in 145 + I.vcat [ summary; I.void 0 1; detail_view ] 88 146 |> Ui.atom 89 147 |> Ui.keyboard_area (function 90 148 | `Escape, [] ->