alacritty / alacritty

A cross-platform, OpenGL terminal emulator.

Home Page:https://alacritty.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Implement scrollback

theduke opened this issue Β· comments

Since you got so much pushback on the scrollback support, and mentioned possibly implementing it,
I'm opening this as a tracking issue.

(ps: I also really want scrollback w/o tmux).

I would also love to see scrolling. I fully share your point of view regarding tabs and tiling (I use a tiling window manager, so no need for that). But scrollback is really something basic to me that shouldn't belong in a separate program.

But of course, the classification into "basic" and "not basic" is quite subjective :)

I'm not committing to adding this just yet, but I would like to mention something for those against this decision. If Alacritty were to add scrolling support, it would be as an opt-in feature. When not opting in, the code paths would be completely compiled out, and performance would not suffer.

@jwilm how do you use your terminal without scrollback? πŸ€” (curious)

https://github.com/jwilm/alacritty#about

Instead, it is expected that users of Alacritty make use of a terminal multiplexer such as tmux.

It is worth noting that while Alacritty is the fastest terminal emulator on systems without the Mesa bug, "Alacritty + tmux" is actually slower than some other terminals which provide scrollback without tmux.

Therefore, if you are only using tmux to get scrollback and are not interested in its other features, Alacritty is not your fastest option anymore.

Besides scrollback tmux handles window resizing with lines wrapping. I've tried many lightweight terminals - each one was buggy with this. So it was the main reason why I started using tmux.

Alacritty could be the first one that gets it right :)

@kurnevsky @dbrgn The 0.8.x releases of xfce4-terminal (released during the last 6 months) have been great at wrapping lines for me. XFCE is also known to be quite minimal and not requiring a lot of dependencies. If you're still looking for a good minimal terminal with scrollback and line wrap I suggest you try it.

Perhaps I have a rather niche use case, but I find scrollback an extremely important feature. Instead of using tmux like it suggests in the README, I use i3 to handle tabs and other window layout needs. However of course it won't handle scrollback for me.

PS: I know how annoying it can be for random users to whine about lacking features.. So I thought I could offer to try and implement this in my spare time. I have about a year of experience using Rust 'as a hobbyist' on weekends. The problem is, I have no experience with terminal emulators and it might take a while to get my head around this codebase.

Thanks for the feedback @neon64!

Perhaps I have a rather niche use case, but I find scrollback an extremely important feature. Instead of using tmux like it suggests in the README, I use i3 to handle tabs and other window layout needs. However of course it won't handle scrollback for me.

This was actually a rather common sentiment in response to the initial Alacritty announcement. I've actually switched to using i3 and have relegated my own use of tmux to remote machines. As such, I'm now in a similar boat wishing for scrollback πŸ˜†.

PS: I know how annoying it can be for random users to whine about lacking features..

Quite the contrary, actually! It's incredibly helpful to hear what users want. This is part of how features are prioritized.

So I thought I could offer to try and implement this in my spare time. I have about a year of experience using Rust 'as a hobbyist' on weekends. The problem is, I have no experience with terminal emulators and it might take a while to get my head around this codebase.

I would be more than happy to help acquaint you with the codebase. I haven't (yet) put much thought into how scrollback should be implemented, but I do have a few initial thoughts:

  • [Requirement] Must be able to opt-in/out via compile time feature flag. The opt-out version should be as performant as current versions which don't support scrollback.
  • Probably want to store list of Vec<Row<Cell>> as the scrollback buffer.
  • Chief challenge is identifying efficient way to move Rows between the grid and the scrollback buffer.
  • Maybe the Grid should become a view into the scroll/line buffer?

Quite the contrary, actually! It's incredibly helpful to hear what users want. This is part of how features are prioritized

a scheduled pre-build build, distributed by homebrew cask would cool πŸ‘

Btw @neon64, if you want to ask questions about the code, I'd be more than happy to talk about it in our IRC channel.

Thanks for the assistance @jwilm - I'll have a look myself over the next few days and see if I can do anything...

A few specific use cases where tmux for scrolling can result in a pretty unstable experience:

  1. Adding tmux to bashrc has the potential to lock user out of the system.
  2. Abandoned sessions quickly pile up due to window kill and reuse. It is not obvious how to solve this in a way that would keep the tmux session log tidy.

@denten I have no such problems. I start tmux with this in my .bashrc.

Thanks @algesten. Tmux has the potential to lock up the system when logging in without a display/login manager due to the way it attaches to x / screens. My .bashrc looked more or less the same as yours. Both Arch and Debian wikis discuss the problem and warn against starting tmux automatically with each bash session. I manged to fix it on my system with much effort (launch Arch from USB, mount drive, revert the .bashrc changes).

My point is that starting tmux on each session just for scrollback is far from "simple" as the Readme suggests. It has pretty significant and non-obvious side effects which include affecting system login behavior and clipboard behavior.

Sessions are another point of complexity. Tmux is not really made to be managed externally. Like many users, I launch and kill hundreds of terminal windows, where I do not want to attach to an existing session. This quickly results in a mountain of abandoned Tmux sessions. I am sure it is possible to figure a way out of it, or to change the way I use my window manager, but that is not really the point. I just want scrollback, not the added baggage of a complex and powerful tool like Tmux.

I am adding these notes to help developers understand the effects of their design decision not to include a basic feature like scrollback. In my case, after losing about a day on battling w/ Alacritty, I went back to gnome-terminal (which by the way is pretty fast in its own right).

@denten it seems the decision that scrollback will be accepted as an alacritty feature is done.
As i understand it, it's just a matter of someone finding the time to do the work.

@torpak that's right!

re: starting tmux in bashrc, I simply maintain two shortcuts:
$TERMINAL -e tmux to open a terminal with tmux.
$TERMINAL to open a terminal without it.

This fixes both issues given:

  1. You cannot lock yourself out if by default you're not launching tmux (of course, your default shortcut does)
  2. Abandoned sessions are no longer needed - if you're just planning to attach to an existing session, you can use the 2nd shortcut and immediately exec tmux a...

This isn't an issue with tmux not being made to be managed externally, but rather not intended to be shoehorned into something that's meant to be initializing your shell - putting anything of that sort in there is bound to potentially cause similar problems.

Mostly leaving this here for people that assume that adding some line to their rcs is the one-true-way:tm: to launch tmux, and are weary of the issues that are bound to come along if one does that.

Would there be a possibility of integrating with tmux for this scrollback, similar to how iTerm2 does it, and also planned to be implemented by Terminator?

@jwilm I've been trying to take your suggestion "Maybe the Grid should become a view into the scroll/line buffer?" on board, and see if it will work when the Grid is a view into a VecDeque. I chose VecDeque because it I can push_back to add new lines and then pop_front to remove the oldest entries once the buffer reaches a defined maximum length (eg: 10,000). However I must admit I know nothing about the internals of these data structures and therefore probably can't aim for optimum performance. Already I fear that VecDeque will be problematic because the memory isn't contiguous so I can't slice it etc...

The other issue I've encountered, is that other terminals (eg: Gnome Terminal) store lines unwrapped (so that upon changing screen size the text can be rewrapped easily), whereas Alacritty doesn't. Its not really a dealbreaker for me, but I thought I'd just point it out because a fix could be part of this scrollback implementation.

Final question, are we aiming for line-by-line or pixel-by-pixel scrolling?Of course pixel-by-pixel looks nicer, but would likely require a bit more work (including modifying the renderer to take a pixel offset, rather than just changing terminal grid impl). Edit: Personally I'm all for pixel because I love eye-candy

Could the idea to integrate with tmux be discussed as well? It sounds really interesting to have one scrollback instead of two independent ones, but I see quite a few πŸ‘Ž - what are the drawbacks of that approach?

What needs integrating? Tmux can already provide scrollback to alacritty. Additional integration will do nothing to help people who don't use tmux.

I think @maximbaz is referring to how iTerm uses their own GUI to display tmux panes/windows etc.. thereby making it look nicer etc...

I do agree that tmux integration would be a nice feature to have, but imho Alacritty should be focusing on its own scrollback system first (at least that's what I'm trying to do... but hey it's open source right πŸ˜ƒ)

could we close this issue or open one that actually concerns this feature?

Regarding the question of line-by-line or pixel-by-pixel scrolling I think the pixel option would be the much better one. While it is a purely cosmetic change it will help make feel alacritty much smoother, I think a modern terminal emulator should aim to 'feel' as good as possible.

commented

Pixel-by-pixel scrolling would require more work, though, so I think line-by-line scrolling should be implemented first.

I am also interested in this feature.
A simple time find in my home directory runs twice as fast with alacritty than Konsole(KDE)(3s vs 6s).
alacritty would be nice to reduce compilation times(a lot of time wasted on a bunch of output) without having to redirect output. Scrolling still necessary to analyze potential compilation problems(again, when not redirecting).

@lilianmoraru in the mean time, if you dev cycle with cargo check --color=always 2>&1 | less, you get scrollback in a pager and can see all the errors.

commented

@tbodt perhaps you be happy to hear that I have scrollback like 80% working on my own fork. However it is still probably a little way before being merged for these reasons:

  • only works with the keyboard (hooking it up to mouse scroll should be like 4 lines of code tho)
  • I haven't fixed the cursor yet
  • I need to implement the correct behaviour when scrolling back while a command is still outputting quickly. ie: the visible region moves with the newest lines, until you start scrolling back and then the visible region will stay put unless you scroll more (I hope that makes sense?)
  • it has probably broken some of the more advanced vt features (eg: scroll margins). I've only tested it with fish shell and a few basic commands so far (ls, find, also 'full-screen': htop, vim)
  • performance could be shocking. At the moment it allocates a new Row for every new line until max_scrollback is reached - then it reuses the old oldest Row. The only workaround I can think of right now is to preallocate all Rows (perhaps 10,000 of them) which means initially higher memory usage.
  • I fear that my entire implementation will need to be reworked in order to support reflow on resize
  • I add two new depencies for minimal gain (I could just write a 'specialized' version just for alacritty but instead chose to use the generic one).
  • probably more :D

So yeah when I have time I'm gradually working through these. And if anybody wants to try out the 'alpha' version right now I'll push it to my own Github when I get back to my laptop.

commented

@neon64 alpha scrollback implementation? yes please!

@tbodt re: less, you can pass less options via command line or LESS= env var which will make it behave better. I currently have LESS=FRSX:

F: quit-if-one-screen
R: RAW-CONTROL-CHARS: allow color control chars to be interpreted
S: chop-long-lines (instead of wrap)
X: no-init: do not send terminal control chars on init/exit which could do things like clear the screen.

Still not as great as real scrollback, but should make the wrap-a-command-that-will-likely-have-pages-of-history-with-less case more useful.

Sorry guys for the delay pushing my implementation, I wanted to 'polish' my changes just a little bit before uploading them. Now the cursor works better and you can actually scroll with the mouse instead of just the keyboard. However (at least on my machine) it flickers sometimes.

You can view/compile the fork here.

@neon64 fantastic work! I've just had an opportunity to try your branch on my MBP, and it seems to work really well. Since you hadn't gotten to it yet, I put together a patch for trackpad scrolling. Feel free to add to your branch! It's admittedly hacked together because I was eager to try scrolling. 😁

diff --git a/src/input.rs b/src/input.rs
index a5bc658..418d217 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -27,6 +27,7 @@ use copypasta::{Clipboard, Load, Buffer};
 use glutin::{ElementState, VirtualKeyCode, MouseButton};
 use glutin::{Mods, mods};
 use glutin::{TouchPhase, MouseScrollDelta};
+use num::Signed;
 
 use config;
 use event::{ClickState, Mouse};
@@ -354,24 +355,52 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
     }
 
     pub fn on_mouse_wheel(&mut self, delta: MouseScrollDelta, phase: TouchPhase) {
-        if let MouseScrollDelta::LineDelta(_columns, lines) = delta {
-            if lines != 0.0 {
-                let scroll_sensitivity = 5.0;
-                self.ctx.mouse_mut().scroll_line += lines * scroll_sensitivity;
-                if self.ctx.mouse_mut().scroll_line.abs() > 1.0 {
-                    // get and reset the counter
-                    let amount_float = self.ctx.mouse_mut().scroll_line;
-                    self.ctx.mouse_mut().scroll_line = 0.0;
-
-                    let amount = AbsoluteLine(amount_float.abs().round() as usize);
-                    if amount_float > 0.0 {
-                        // scroll up
-                        self.ctx.move_visible_region_up(amount);
-                    } else {
-                        // scroll down
-                        self.ctx.move_visible_region_down(amount);
+        let mut touch_line_delta = 0;
+
+        match delta {
+            MouseScrollDelta::LineDelta(ref _columns, ref lines) => {
+                if *lines != 0.0 {
+                    let scroll_sensitivity = 5.0;
+                    self.ctx.mouse_mut().scroll_line += lines * scroll_sensitivity;
+                    if self.ctx.mouse_mut().scroll_line.abs() > 1.0 {
+                        // get and reset the counter
+                        let amount_float = self.ctx.mouse_mut().scroll_line;
+                        self.ctx.mouse_mut().scroll_line = 0.0;
+
+                        let amount = AbsoluteLine(amount_float.abs().round() as usize);
+                        if amount_float > 0.0 {
+                            // scroll up
+                            self.ctx.move_visible_region_up(amount);
+                        } else {
+                            // scroll down
+                            self.ctx.move_visible_region_down(amount);
+                        }
                     }
-                    
+                }
+            },
+            MouseScrollDelta::PixelDelta(ref _x, ref y) => {
+                match phase {
+                    TouchPhase::Started => {
+                        // Reset offset to zero
+                        self.ctx.mouse_mut().scroll_px = 0;
+                    },
+                    TouchPhase::Moved => {
+                        self.ctx.mouse_mut().scroll_px += *y as i32;
+                        let height = self.ctx.size_info().cell_height as i32;
+
+                        while self.ctx.mouse_mut().scroll_px.abs() >= height {
+                            let button = if self.ctx.mouse_mut().scroll_px > 0 {
+                                touch_line_delta -= 1;
+                                self.ctx.mouse_mut().scroll_px -= height;
+                                self.ctx.move_visible_region_up(AbsoluteLine(1));
+                            } else {
+                                touch_line_delta += 1;
+                                self.ctx.mouse_mut().scroll_px += height;
+                                self.ctx.move_visible_region_down(AbsoluteLine(1));
+                            };
+                        }
+                    },
+                    _ => (),
                 }
             }
         }
@@ -394,28 +423,14 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
                 }
             },
             MouseScrollDelta::PixelDelta(_x, y) => {
-                match phase {
-                    TouchPhase::Started => {
-                        // Reset offset to zero
-                        self.ctx.mouse_mut().scroll_px = 0;
-                    },
-                    TouchPhase::Moved => {
-                        self.ctx.mouse_mut().scroll_px += y as i32;
-                        let height = self.ctx.size_info().cell_height as i32;
-
-                        while self.ctx.mouse_mut().scroll_px.abs() >= height {
-                            let button = if self.ctx.mouse_mut().scroll_px > 0 {
-                                self.ctx.mouse_mut().scroll_px -= height;
-                                64
-                            } else {
-                                self.ctx.mouse_mut().scroll_px += height;
-                                65
-                            };
-
-                            self.normal_mouse_report(button);
-                        }
-                    },
-                    _ => (),
+                if touch_line_delta > 0 {
+                    for _ in 0..touch_line_delta {
+                        self.normal_mouse_report(65);
+                    }
+                } else if touch_line_delta < 0 {
+                    for _ in 0..(touch_line_delta.abs()) {
+                        self.normal_mouse_report(64);
+                    }
                 }
             }
         }

How would you feel about opening a PR to discuss your implementation? Seems to be working pretty well for me (have only tested very lightly, though).

By the way, what were you talking about with performance issues? At least on my machine, the difference seems to be very small.

I tested this for a bit and it works really well for me! Thanks!
Earlier today I managed to somehow crash the terminal with out of bounds errors (two times in a row) by doing some crazy resizing (I am using i3 which might produce strange edge cases) but I can't reproduce that currently.
If anyone else could mess around with resizing a bit I would be grateful.

Thanks for the feedback @jwilm and @hatzel. Regarding the crashing on resize, I experienced that too (for me it was go to fullscreen, scroll up, then exit fullscreen). And yeah I was testing on a MBP too but for some reason I only got LineDelta (probably because it's Sway/Wayland/Linux not supporting it yet). I'll open a PR if that's the best place to discuss further, but there's still lots to do like fix/write tests

@neon64 I think a PR would be best for discussing your particular implementation of scrollback.

if you can "compile" the terminal output into GPU commands why not save those GPU commands for later use?

wouldn't that make scrolling easier?

(might be weird with things that change the terminal as opposed to adding new lines, tho...)

Any progress on this?

I have been using Alacritty built with scrollback from a0b55ca . I haven't experienced any bug so far (I am running it on Fedora 27, Gnome on X11).

Since there seems to be a strong push for the scrollback feature in alacritty, maybe it can be merged without having the "whole package" (reflow and scrollback buffer search)? As a side effect, doing this will provide feedback on the scrollback feature, which can be useful for implementing the reflow and search features.

@zakora I second that.

Is it possible this conflicts with the alacritty as a library branch?

Thats the main thing I could think that would hold back this merge...

Why would it be an issue for alacritty as a library? Can't the library functionality exists regardless of the scrolling feature?

It was just speculation

Gotcha, I thought there was an actual limitation there and, if it did, I'd like to know.

Another +1 here for built-in scrollback. I don't mind whether it's an opt-in or not.

Currently building @neon64's scrollback commit to see how that works for me. Will report back later.

@Sas-18, you may want to try out the scrollback feature from PR #1147 . I am currently running it (on commit 0d56818) without any issues.

@zakora you read my mind; have already tried it :) (running it right now) and it works great, as far as the scrolling goes. For the record, Neon64's scrollback implementation also appeared to work well for me; I didn't do any performance testing or compare the two implementations, but given that (if I understand) the development is going in a direction NOT the Neon64 implementation, I'll continue to work with the jwilm scrollback branch for the time being.
It works really nice, except the bug which makes it not render if it loses focus :/ I'm possibly writing an issue about it now, as it doesn't quite match symptoms of the similar Issues regarding not rendering.

So how do I scroll? I'm confused. Mouse wheel does nothing.

As long as this issue is still open, alacritty does not yet implement scrollback in the master branch.

@sajattack If you take the time to read from the first comment in this issue it points to scrolling by using tmux. If you don't know what it is, look it up, it is a terminal multiplexer.

Hopefully scrollback will be optional. I'm using Alacritty mostly because it doesn't have scrollback.

@yegortimoshenko The scrollback history size is already completely up to the user to choose. So it's already possible to disable scrollback history, no worries! :)

commented

Would love the option. The faux scrollback in Vim works really natively, and its always a surprise when there's a stack trace to big for my window. Looking forward to trying this setup via #1147.

Any idea when this will be merged? It's been open quite a while now πŸ˜„. Thanks!

From a technical perspective I think most issues on scrollback are resolved. A longer testing period is always a good thing but as far as I know this branch already has a fair share of users.

At this point it comes down to jwilm when scrollback is ready for merging. I'm not aware of anything that can be done to accelerate the process by anyone else.

I've been using the scrollback branch for a few weeks and haven't had any problems at all! It might be difficult to get a sense of exactly how many people are using it, but I imagine the number is non-trivial.

Perhaps people can add a reaction to this comment if you're already using the scrollback branch?

Thanks for the feedback @shazow, it's always easier to see when things are broken than when things are working well. So feedback like this is much appreciated.

I've just checked out the latest version of this branch, compiled and installed it with cargo deb. I have been running an old version of this branch for quite some time.

Having a few problems. I've noticed that holding down keys doesn't work. The window also has a strange decoration with red/yellow/green buttons in the top right. Additionally, cargo deb gets stuck when running it for a second time, and I had to cargo clean unfortunately.

@c-edw can you verify those problems are specific to the scrollback branch?

@kpcyrd Nope, they're on master too, not sure why I thought it was restricted to scrollback.

@c-edw

The window also has a strange decoration with red/yellow/green buttons in the top right.

Hey, it seems that you're using Linux with Wayland (default on latest Gnome DE and some Linux distros). If that's the case, you should run Alacritty with Wayland-backend disabled as stated in the "Edit" of this reply: #97 (comment) (env WAYLAND_DISPLAY= alacritty).

@nirfse Thanks for the info. I remember having to do this a while ago. Unfortunately, I'm now getting Illegal instruction (core dumped) when running it like this, even though the workaround worked fine before. This issue is on master though, don't let it halt anything here πŸ˜„.

@c-edw That was a build error due to one of our dependencies. It has already been resolved on both master and scrollback.

@chrisduerr Great, works! Everything seems to be working for me then, I will continue to test the scrollback branch until it is merged.

Hi all,
I just wanna say thank you for this feature. I use it since january as my primary terminal and I never find an issue in my daily use of it.
I use AUR package alacritty-scrollback-git with Xorg installed.

for context #1147 added scrollback. This was the alacritty blocker for me, I can't wait to use it! Thanks for the hard work.