jesseduffield.lazygit/pkg/gocui
Stefan Haller 585c7f126d Cache each line's wrapping so scrolling doesn't re-wrap the whole buffer
refreshViewLinesIfNeeded re-wrapped every line of the buffer whenever
the view was tainted. That's cheap for short content, but scrolling a
long diff calls it constantly: adjustDownwardScrollAmount queries
ViewLinesHeight on every scroll event, and each newly-read line taints
the view, so every notch re-wrapped the entire buffer. Wrapping measures
each cell's width (uniseg) and allocates per line, so once you'd scrolled
far enough down the diff, scrolling turned sluggish - the cost grew with
how much had been read. (A CPU profile of scrolling deep in a long diff
put 77% of the time in lineWrap, reached almost entirely via
ViewLinesHeight rather than draw.)

Cache each line's wrapped result on the lineType, keyed by the width it
was wrapped at, and only re-wrap lines that have actually changed since
the last refresh. A firstDirtyLine index, updated in the same three
places that set `tainted` (write, clearViewLines' callers, SetHighlight),
marks the lowest line that might have changed; lines below it with a
matching cached width reuse their cached wrapping. The cache lives on the
line, so it's freed with the line when the view's content is replaced
(e.g. selecting a different commit) - it doesn't accumulate across a
session.

The wrapping cost per scroll now scales with the number of lines just
read, not with the total size of the buffer, so scrolling stays smooth
no matter how far down you are.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 09:32:35 +02:00
..
attribute.go Bump tcell dependency to v3 2026-04-30 22:14:26 +02:00
AUTHORS Copy gocui files into lazygit repo under pkg/gocui 2026-04-30 14:29:08 +02:00
CHANGES_tcell.md Copy gocui files into lazygit repo under pkg/gocui 2026-04-30 14:29:08 +02:00
CODE_OF_CONDUCT.md Copy gocui files into lazygit repo under pkg/gocui 2026-04-30 14:29:08 +02:00
CONTRIBUTING.md Copy gocui files into lazygit repo under pkg/gocui 2026-04-30 14:29:08 +02:00
doc.go Remove dead Modifier field from keybindings 2026-05-06 09:51:23 +02:00
edit.go Convert keybinding fields to Keybinding 2026-05-25 15:32:47 +02:00
escape.go Materialize cursor-forward escapes as space runs 2026-07-03 18:47:15 +02:00
escape_test.go Materialize cursor-forward escapes as space runs 2026-07-03 18:47:15 +02:00
flush_test.go When drawing tainted views in ForceFlushViewsContentOnly, also draw views that overlap them 2026-05-09 13:58:33 +02:00
gui.go Add IsUIThread and OnUIThreadAndWait to gocui 2026-07-07 18:09:33 +02:00
gui_others.go Copy gocui files into lazygit repo under pkg/gocui 2026-04-30 14:29:08 +02:00
gui_windows.go Fix linter warnings 2026-04-30 14:29:08 +02:00
key.go Move modifiers into Key 2026-04-30 22:22:53 +02:00
keybinding.go Remove dead Modifier field from keybindings 2026-05-06 09:51:23 +02:00
LICENSE Copy gocui files into lazygit repo under pkg/gocui 2026-04-30 14:29:08 +02:00
README.md Copy gocui files into lazygit repo under pkg/gocui 2026-04-30 14:29:08 +02:00
scrollbar.go Copy gocui files into lazygit repo under pkg/gocui 2026-04-30 14:29:08 +02:00
scrollbar_test.go Copy gocui files into lazygit repo under pkg/gocui 2026-04-30 14:29:08 +02:00
task.go Exclude view-buffer render tasks from the busy query 2026-07-07 18:09:33 +02:00
task_manager.go Add background tasks and a synchronous busy query to gocui 2026-07-07 18:09:33 +02:00
task_manager_test.go Add background tasks and a synchronous busy query to gocui 2026-07-07 18:09:33 +02:00
tcell_driver.go Let integration tests post a focus event 2026-06-23 14:15:18 +02:00
text_area.go Add a forwardDeleteWord keybinding 2026-04-30 22:31:44 +02:00
text_area_test.go Fix linter warnings 2026-04-30 14:29:08 +02:00
view.go Cache each line's wrapping so scrolling doesn't re-wrap the whole buffer 2026-07-09 09:32:35 +02:00
view_test.go Materialize cursor-forward escapes as space runs 2026-07-03 18:47:15 +02:00

GOCUI - Go Console User Interface

CircleCI CodeCov Go Report Card GolangCI GoDoc GitHub tag (latest SemVer)

Minimalist Go package aimed at creating Console User Interfaces. A community fork based on the amazing work of jroimartin

Features

  • Minimalist API.
  • Views (the "windows" in the GUI) implement the interface io.ReadWriter.
  • Support for overlapping views.
  • The GUI can be modified at runtime (concurrent-safe).
  • Global and view-level keybindings.
  • Mouse support.
  • Colored text.
  • Customizable editing mode.
  • Easy to build reusable widgets, complex layouts...

About fork

This fork has many improvements over the original work from jroimartin.

  • Written ontop of TCell
  • Better wide character support
  • Support for 1 Line height views
  • Better support for running in docker container
  • Customize frame colors
  • Improved code comments and quality
  • Many small improvements
  • Change Visibility of views

For information about this org see: awesome-gocui/about.

Installation

Execute:

$ go get github.com/awesome-gocui/gocui

Documentation

Execute:

$ go doc github.com/awesome-gocui/gocui

Or visit godoc.org to read it online.

Example

See the _example folder for more examples

package main

import (
	"fmt"
	"log"

	"github.com/awesome-gocui/gocui"
)

func main() {
	g, err := gocui.NewGui(gocui.OutputNormal, true)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.SetManagerFunc(layout)

	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
		log.Panicln(err)
	}

	if err := g.MainLoop(); err != nil && !gocui.IsQuit(err) {
		log.Panicln(err)
	}
}

func layout(g *gocui.Gui) error {
	maxX, maxY := g.Size()
	if v, err := g.SetView("hello", maxX/2-7, maxY/2, maxX/2+7, maxY/2+2, 0); err != nil {
		if !gocui.IsUnknownView(err) {
			return err
		}

		if _, err := g.SetCurrentView("hello"); err != nil {
			return err
		}

		fmt.Fprintln(v, "Hello world!")
	}

	return nil
}

func quit(g *gocui.Gui, v *gocui.View) error {
	return gocui.ErrQuit
}

Screenshots

r2cui

_examples/demo.go

_examples/dynamic.go

Projects using gocui

  • komanda-cli: IRC Client For Developers.
  • vuls: Agentless vulnerability scanner for Linux/FreeBSD.
  • wuzz: Interactive cli tool for HTTP inspection.
  • httplab: Interactive web server.
  • domainr: Tool that checks the availability of domains based on keywords.
  • gotime: Time tracker for projects and tasks.
  • claws: Interactive command line client for testing websockets.
  • terminews: Terminal based RSS reader.
  • diagram: Tool to convert ascii arts into hand drawn diagrams.
  • pody: CLI app to manage Pods in a Kubernetes cluster.
  • kubexp: Kubernetes client.
  • kcli: Tool for inspecting kafka topics/partitions/messages.
  • fac: git merge conflict resolver
  • jsonui: Interactive JSON explorer for your terminal.
  • cointop: Interactive terminal based UI application for tracking cryptocurrencies.
  • lazygit: simple terminal UI for git commands.
  • lazydocker: The lazier way to manage everything docker.

Note: if your project is not listed here, let us know! :)