docs/dev/Codebase_Guide.md
pkg/app: Contains startup code, initialises a bunch of stuff like logging, the user config, etc, before starting the gui. Catches and handles some errors that the gui raises.pkg/app/daemon: Contains code relating to the lazygit daemon. This could be better named: it's is not a daemon in the sense that it's a long-running background process; rather it's a short-lived background process that we pass to git for certain tasks, like GIT_EDITOR for when we want to set the TODO file for an interactive rebase.pkg/cheatsheet: Generates the keybinding cheatsheets in docs/keybindings.pkg/commands/git_commands: All communication to the git binary happens here. So for example there's a Checkout method which calls git checkout.pkg/commands/oscommands: Contains code for talking to the OS, and for invoking commands in generalpkg/commands/git_config: Reading of the git config all happens here.pkg/commands/hosting_service: Contains code that is specific to git hosting services (aka forges).pkg/commands/models: Contains model structs that represent commits, branches, files, etc.pkg/commands/patch: Contains code for parsing and working with git patchespkg/common: Contains the Common struct which holds common dependencies like the logger, i18n, and the user config. Most structs in the code will have a field named c which holds a common struct (or a derivative of the common struct).pkg/config: Contains code relating to the Lazygit user config. Specifically pkg/config/user_config/go defines the user config struct and its default values. See below for some important information about using it.pkg/constants: Contains some constant strings (e.g. links to docs)pkg/env: Contains code relating to setting/getting environment variablespkg/i18n: Contains internationalised stringspkg/integration: Contains end-to-end testspkg/jsonschema: Contains generator for user config JSON schema.pkg/logs: Contains code for instantiating the logger and for tailing the logs via lazygit --logspkg/tasks: Contains code for running asynchronous tasks: mostly related to efficiently rendering command output to the main window.pkg/theme: Contains code related to colour themes.pkg/updates: Contains code related to Lazygit updates (checking for update, download and installing the update)pkg/utils: Contains lots of low-level helper functionspkg/gui: Contains code related to the gui. We've still got a God Struct in the form of our Gui struct, but over time code has been moved out into contexts, controllers, and helpers, and we intend to continue moving more code out over time.pkg/gui/context: Contains code relating to contexts. There is a context for each view e.g. a branches context, a tags context, etc. Contexts manage state related to the view and receive keypresses.pkg/gui/controllers: Contains code relating to controllers. Controllers define a list of keybindings and their associated handlers. One controller can be assigned to multiple contexts, and one context can contain multiple controllers.pkg/gui/controllers/helpers: Contains code that is shared between multiple controllers.pkg/gui/filetree: Contains code relating to the representation of filetrees.pkg/gui/keybindings: Contains code for mapping between keybindings and their labelspkg/gui/mergeconflicts: Contains code relating to the handling of merge conflictspkg/gui/modes: Contains code relating to the state of different modes e.g. cherry picking mode, rebase mode.pkg/gui/patch_exploring: Contains code relating to the state of patch-oriented views like the staging view.pkg/gui/popup: Contains code that lets you easily raise popupspkg/gui/presentation: Contains presentation code i.e. code concerned with rendering content inside viewspkg/gui/services/custom_commands: Contains code related to user-defined custom commands.pkg/gui/status: Contains code for invoking loaders and toastspkg/gui/style: Contains code for specifying text styles (colour, bold, etc)pkg/gui/types: Contains various gui-specific types and interfaces. Lots of code lives here to avoid circular dependenciesvendor/github.com/jesseduffield/gocui: Gocui is the underlying library used for handling the gui event loop, handling keypresses, and rendering the UI. It defines the View struct which our own context structs build upon.pkg/config/user_config.go: defines the user config and default valuespkg/gui/keybindings.go: defines keybindings which have not yet been moved into a controller (originally all keybindings were defined here)pkg/gui/controllers.go: links up controllers with contextspkg/gui/controllers/helpers/helpers.go: defines all the different helper structspkg/commands/git.go: defines all the different git command structspkg/gui/gui.go: defines the top-level gui state and gui initialisation/run codepkg/gui/layout.go: defines what happens on each renderpkg/gui/controllers/helpers/window_arrangement_helper.go: defines the layout of the UI and the size/position of each windowpkg/gui/context/context.go: defines the different contextspkg/gui/context/setup.go: defines initialisation code for all contextspkg/gui/context.go: manages the lifecycle of contexts, the context stack, and focus changes.pkg/gui/types/views.go: defines viewspkg/gui/views.go: defines the ordering of views (front to back) and their initialisation codepkg/gui/gui_common.go: defines gui-specific methods that all controllers and helpers have access topkg/i18n/english.go: defines the set of i18n strings and their English valuespkg/gui/controllers/helpers/refresh_helper.go: manages refreshing of models. The refresh helper is typically invoked at the end of an action to re-load affected models from git (e.g. re-load branches after doing a git pull)pkg/gui/controllers/quit_actions.go: contains code that runs when you hit 'escape' on a view (assuming the view doesn't define its own escape handler)vendor/github.com/jesseduffield/gocui/gui.go: defines the gocui gui structvendor/github.com/jesseduffield/gocui/view.go: defines the gocui view structIn terms of dependencies, controllers sit at the highest level, so they can refer to helpers, contexts, and views (although it's preferable for view-specific code to live in contexts). Helpers can refer to contexts and views, and contexts can only refer to views. Views can't refer to contexts, controllers, or helpers.
c which contains a 'common' struct: a struct containing a bag of dependencies that most structs of the same layer require. For example if you want to access a helper from a controller you can do so with self.c.Helpers.MyHelper.The event loop is managed in the MainLoop function of vendor/github.com/jesseduffield/gocui/gui.go. Any time there is an event like a key press or a window resize, the event will be processed and then the screen will be redrawn. This involves calling the layout function defined in pkg/gui/layout.go, which lays out the windows and invokes some on-render hooks.
Often, as part of handling a keypress, we'll want to run some code asynchronously so that it doesn't block the UI thread. For this we'll typically run self.c.OnWorker(myFunc). If the worker wants to then do something on the UI thread again it can call self.c.OnUIThread(myOtherFunc).
The UserConfig struct is loaded from lazygit's global config file (and possibly repo-specific config files). It can be re-loaded while lazygit is running, e.g. when the user edits one of the config files. In this case we should make sure that any new or changed config values take effect immediately. The easiest way to achieve this is what we do in most controllers or helpers: these have a pointer to the common.Common struct, which contains the UserConfig, and access it from there. Since the UserConfig instance in common.Common is updated whenever we reload the config, the code can be sure that it always uses an up-to-date value, and there's nothing else to do.
If that's not possible for some reason, see if you can add code to Gui.onUserConfigLoaded to update things from the new config; there are some examples in that function to use as a guide. If that's too hard to do too, add the config to the list in Gui.checkForChangedConfigsThatDontAutoReload so that the user is asked to quit and restart lazygit.
Before we had controllers and contexts, all the code lived directly in the gui package under a gui God Struct. This was fairly bloated and so we split things out to have a better separation of concerns. Nonetheless, it's a big effort to migrate all the code so we still have some logic in the gui struct that ought to live somewhere else. Likewise, we have some keybindings defined in pkg/gui/keybindings.go that ought to live on a controller (all keybindings used to be defined in that one file).
The new structure has its own problems: we don't have a clear guide on whether code should live in a controller or helper. The current approach is to put code in a controller until it's needed by another controller, and to then extract it out into a helper. We may be better off just putting code in helpers to start with and leaving controllers super-thin, with the responsibility of just pairing keys with corresponding helper functions. But it's not clear to me if that would be better than the current approach.