11use anyhow:: { bail, Context , Result } ;
22use async_fs:: File ;
3+ use async_trait:: async_trait;
34use futures:: future:: RemoteHandle ;
45use futures:: io:: BufReader ;
56use futures:: prelude:: * ;
@@ -11,9 +12,9 @@ use gtk::prelude::*;
1112use gtk:: subclass:: prelude:: * ;
1213use gtk:: CompositeTemplate ;
1314use gtk:: TemplateChild ;
14- use log:: { debug, info} ;
15+ use log:: { debug, info, warn } ;
1516use once_cell:: sync:: Lazy ;
16- use std:: cell:: { Cell , RefCell } ;
17+ use std:: cell:: { Cell , Ref , RefCell } ;
1718use std:: fmt:: Write ;
1819use std:: marker:: PhantomData ;
1920use std:: pin:: Pin ;
@@ -28,7 +29,7 @@ use hypertext::HypertextEvent;
2829
2930const BYTES_BEFORE_YIELD : usize = 1024 * 10 ;
3031
31- #[ derive( Debug , Clone , PartialEq ) ]
32+ #[ derive( Clone ) ]
3233pub struct HistoryItem {
3334 pub url : url:: Url ,
3435 pub cache : Rc < RefCell < Option < Vec < u8 > > > > ,
@@ -42,17 +43,55 @@ pub struct HistoryStatus {
4243 pub ( crate ) available : usize ,
4344}
4445
46+ #[ derive( Default ) ]
47+ pub struct History {
48+ items : Vec < HistoryItem > ,
49+ index : Option < usize > ,
50+ }
51+
52+ impl History {
53+ fn push ( & mut self , item : HistoryItem ) -> usize {
54+ let new_index = self . index . map_or ( 0 , |i| i + 1 ) ;
55+ self . index = Some ( new_index) ;
56+ self . items . truncate ( new_index) ;
57+ self . items . push ( item) ;
58+ new_index
59+ }
60+ fn index ( & self ) -> Option < usize > {
61+ self . index
62+ }
63+ fn len ( & self ) -> usize {
64+ self . items . len ( )
65+ }
66+ fn current ( & self ) -> Option < & HistoryItem > {
67+ self . index . map ( |i| & self . items [ i] )
68+ }
69+ fn items ( & self ) -> & [ HistoryItem ] {
70+ & self . items
71+ }
72+ fn set_index ( & mut self , i : usize ) -> bool {
73+ if ( 0 ..self . items . len ( ) ) . contains ( & i) {
74+ self . index = Some ( i) ;
75+ true
76+ } else {
77+ false
78+ }
79+ }
80+ fn go_previous ( & mut self ) -> bool {
81+ self . set_index ( self . index . unwrap_or ( 0 ) . saturating_sub ( 1 ) )
82+ }
83+ }
84+
4585pub mod imp {
4686
4787 pub use super :: * ;
48- #[ derive( Debug , Default , Properties , CompositeTemplate ) ]
88+ #[ derive( Default , Properties , CompositeTemplate ) ]
4989 #[ template( resource = "/com/ranfdev/Geopard/ui/tab.ui" ) ]
5090 #[ properties( wrapper_type = super :: Tab ) ]
5191 pub struct Tab {
5292 pub ( crate ) gemini_client : RefCell < gemini:: Client > ,
5393 pub ( crate ) config : RefCell < crate :: config:: Config > ,
54- pub ( crate ) history : RefCell < Vec < HistoryItem > > ,
55- pub ( crate ) current_hi : Cell < Option < usize > > ,
94+ pub ( crate ) history : RefCell < History > ,
5695 #[ template_child]
5796 pub ( crate ) scroll_win : TemplateChild < gtk:: ScrolledWindow > ,
5897 #[ template_child]
@@ -120,9 +159,10 @@ pub mod imp {
120159 }
121160 impl Tab {
122161 fn history_status ( & self ) -> HistoryStatus {
162+ let history = self . history . borrow ( ) ;
123163 HistoryStatus {
124- current : self . current_hi . get ( ) . unwrap_or ( 0 ) ,
125- available : self . history . borrow ( ) . len ( ) ,
164+ current : history . index ( ) . unwrap_or ( 0 ) ,
165+ available : history. len ( ) ,
126166 }
127167 }
128168 }
@@ -149,48 +189,44 @@ impl Tab {
149189
150190 // If there's an in flight request, the related history item (the last one)
151191 // must be removed
152- if let Some ( in_flight_req) = imp. req_handle . borrow_mut ( ) . take ( ) {
153- if in_flight_req. now_or_never ( ) . is_none ( ) {
154- imp. history . borrow_mut ( ) . pop ( ) ;
155- let i = imp. current_hi . get ( ) . unwrap ( ) ;
156- imp. current_hi . replace ( Some ( i. saturating_sub ( 1 ) ) ) ;
192+ {
193+ let req = imp. req_handle . take ( ) ;
194+ if let Some ( req) = req {
195+ // if the request isn't ready, it's still in flight
196+ if req. now_or_never ( ) . is_none ( ) {
197+ imp. history . borrow_mut ( ) . go_previous ( ) ;
198+ }
157199 }
158200 }
159201
160- let i = self . add_to_history ( HistoryItem {
202+ let body: Rc < RefCell < Option < Vec < u8 > > > > = Rc :: new ( RefCell :: new ( None ) ) ;
203+ let body_weak = Rc :: downgrade ( & body) ;
204+
205+ self . add_to_history ( HistoryItem {
161206 url : url. clone ( ) ,
162- cache : Default :: default ( ) ,
207+ cache : body ,
163208 scroll_progress : 0.0 ,
164209 } ) ;
165- let cache_space = Rc :: downgrade ( & self . imp ( ) . history . borrow ( ) [ i ] . cache ) ;
210+
166211 let this = self . clone ( ) ;
167212 let fut = async move {
168- let cache = this. open_url ( url) . await ;
169- cache_space . upgrade ( ) . map ( |rc| rc . replace ( cache ) ) ;
213+ let data = this. open_url ( url) . await ;
214+ * body_weak . upgrade ( ) . unwrap ( ) . borrow_mut ( ) = data ;
170215 } ;
171- self . spawn_request ( fut) ;
216+ imp. req_handle
217+ . replace ( Some ( glibctx ( ) . spawn_local_with_handle ( fut) . unwrap ( ) ) ) ;
172218 }
173- // FIXME: make history functions simpler
174- fn add_to_history ( & self , item : HistoryItem ) -> usize {
219+ fn add_to_history ( & self , mut item : HistoryItem ) -> usize {
175220 let imp = self . imp ( ) ;
176- let i = {
177- let mut history = imp. history . borrow_mut ( ) ;
178- let i = imp. current_hi . get ( ) ;
179- if let Some ( i) = i {
180- let scroll_progress = imp. scroll_win . vadjustment ( ) . value ( ) ;
181- if let Some ( item) = history. get_mut ( i) {
182- item. scroll_progress = scroll_progress;
183- }
184- history. truncate ( i + 1 ) ;
185- } ;
186- history. push ( item) ;
187- let i = history. len ( ) - 1 ;
188- imp. current_hi . replace ( Some ( i) ) ;
189- i
190- } ;
221+
222+ item. scroll_progress = imp. scroll_win . vadjustment ( ) . value ( ) ;
223+ {
224+ imp. history . borrow_mut ( ) . push ( item) ;
225+ }
226+
191227 self . emit_history_status ( ) ;
192228 self . log_history_position ( ) ;
193- i
229+ imp . history . borrow ( ) . index ( ) . unwrap ( )
194230 }
195231 fn clear_stack_widgets ( & self ) {
196232 let imp = self . imp ( ) ;
@@ -241,6 +277,7 @@ impl Tab {
241277 }
242278 fn open_history ( & self , item : HistoryItem ) -> Pin < Box < dyn Future < Output = ( ) > > > {
243279 let HistoryItem { url, cache, .. } = item;
280+
244281 let cache = cache. borrow ( ) ;
245282 match & * cache {
246283 Some ( cache) => Box :: pin ( self . open_cached ( url, cache. clone ( ) ) ) ,
@@ -272,48 +309,19 @@ impl Tab {
272309 }
273310 }
274311 fn log_history_position ( & self ) {
275- let i = self . imp ( ) . current_hi . get ( ) ;
312+ let i = self . imp ( ) . history . borrow ( ) . index ( ) ;
276313 info ! ( "history position: {i:?}" ) ;
277314 }
278- pub fn previous ( & self ) -> Result < ( ) > {
279- let imp = self . imp ( ) ;
280- let i = {
281- imp. current_hi
282- . get ( )
283- . and_then ( |i| i. checked_sub ( 1 ) )
284- . context ( "going back in history" ) ?
285- } ;
286- imp. current_hi . replace ( Some ( i) ) ;
287- self . log_history_position ( ) ;
288- self . emit_history_status ( ) ;
289-
290- let h = { imp. history . borrow_mut ( ) . get ( i) . cloned ( ) } ;
291- h. map ( |x| self . spawn_request ( self . open_history ( x) ) )
292- . context ( "retrieving previous item from history" )
315+ pub fn previous ( & self ) -> bool {
316+ self . move_in_history ( -1 )
293317 }
294- pub fn next ( & self ) -> Result < ( ) > {
295- let imp = self . imp ( ) ;
296- let i = {
297- imp. current_hi
298- . get ( )
299- . map ( |i| i + 1 )
300- . filter ( |i| * i < imp. history . borrow ( ) . len ( ) )
301- . context ( "going forward in history" ) ?
302- } ;
303- imp. current_hi . replace ( Some ( i) ) ;
304- self . log_history_position ( ) ;
305- self . emit_history_status ( ) ;
306-
307- let h = { imp. history . borrow_mut ( ) . get ( i) . cloned ( ) } ;
308- h. map ( |x| self . spawn_request ( self . open_history ( x) ) )
309- . context ( "retrieving next item from history" )
318+ pub fn next ( & self ) -> bool {
319+ self . move_in_history ( 1 )
310320 }
311321 pub fn reload ( & self ) {
312322 let imp = self . imp ( ) ;
313- let i = imp. current_hi . get ( ) . unwrap ( ) ;
314323
315- if let Some ( h) = imp. history . borrow_mut ( ) . get ( i) {
316- h. cache . replace ( None ) ;
324+ if let Some ( h) = imp. history . borrow_mut ( ) . current ( ) {
317325 self . spawn_request ( self . open_history ( h. clone ( ) ) ) ;
318326 }
319327 }
@@ -664,4 +672,25 @@ impl Tab {
664672 imp. stack . add_child ( & p) ;
665673 imp. stack . set_visible_child ( & p) ;
666674 }
675+ pub fn history_items ( & self ) -> Ref < [ HistoryItem ] > {
676+ Ref :: map ( self . imp ( ) . history . borrow ( ) , |x| x. items ( ) )
677+ }
678+ pub fn move_in_history ( & self , offset : isize ) -> bool {
679+ let moved = {
680+ let mut h = self . imp ( ) . history . borrow_mut ( ) ;
681+ let new_index = if offset > 0 {
682+ h. index ( ) . unwrap_or ( 0 ) + offset as usize
683+ } else {
684+ h. index ( ) . unwrap_or ( 0 ) . saturating_sub ( offset. abs ( ) as usize )
685+ } ;
686+ h. index ( ) != Some ( new_index) && h. set_index ( new_index)
687+ } ;
688+ if moved {
689+ self . spawn_request (
690+ self . open_history ( self . imp ( ) . history . borrow ( ) . current ( ) . unwrap ( ) . clone ( ) ) ,
691+ ) ;
692+ self . emit_history_status ( ) ;
693+ }
694+ moved
695+ }
667696}
0 commit comments