chiark / gitweb /
Fill in percentage in file status lines.
authorSimon Tatham <anakin@pobox.com>
Mon, 1 Jan 2024 14:02:05 +0000 (14:02 +0000)
committerSimon Tatham <anakin@pobox.com>
Mon, 1 Jan 2024 14:02:05 +0000 (14:02 +0000)
I was putting that off because I had a half-formed clever idea about
trying to do linear regression on the posts we _have_ formatted to the
current width, and using it to estimate the likely line height of the
ones we haven't. But then I decided that was either the perfect being
the enemy of the good, or a silly idea that was bound to explode in an
edge case, or both, and so I've done something simple instead.

The _main_ purpose is that '100%' means 'nothing more to read' and
anything less means there is. As long as we get that much right, we're
in reasonably good shape.

src/file.rs

index c2c7e583166debc9debc78e125c7a6b22d8e257a..774d97c1e7e0d91976277d0a9316705f119e72fe 100644 (file)
@@ -476,10 +476,32 @@ impl<Type: FileType, Source: FileDataSource>
         } else {
             fs.add(Space, "Down", 99)
         };
-        let fs = fs.add(Pr('q'), "Exit", 100)
-            .finalise();
+        let fs = fs.add(Pr('q'), "Exit", 100);
         // FIXME: document more keys
-        // FIXME: best-effort percentage calculation
+
+        // We calculate the percentage through the file in a loose
+        // sort of way, by assuming all items are the same size, and
+        // only calculating a partial item for the one we're actually
+        // in the middle of. This isn't how Mono did it, but Mono
+        // didn't have to dynamically rewrap whenever the window
+        // resized.
+        //
+        // (A robust way to get precise line-based percentages even so
+        // would be to eagerly rewrap the entire collection of items
+        // on every resize, but I don't think that's a sensible
+        // tradeoff!)
+        let fs = {
+            let base = self.contents.first_index();
+            let full_items = (start_item - base) as usize;
+            let total_items = (self.contents.index_limit() - base) as usize;
+            let mult = self.rendered.get(&start_item).unwrap().len();
+            fs.set_proportion(
+                full_items * mult + start_line,
+                total_items * mult)
+        };
+
+        let fs = fs.finalise();
+
         lines.extend_from_slice(&fs.render(w));
 
         (lines, CursorPosition::End)