1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-01-08 04:04:22 +02:00
lazygit/pkg/cheatsheet/generate.go

265 lines
7.3 KiB
Go
Raw Normal View History

// This "script" generates a file called Keybindings_{{.LANG}}.md
// in current working directory.
//
// The content of this generated file is a keybindings cheatsheet.
//
// To generate cheatsheet in english run:
2022-01-04 01:46:14 +02:00
// go run scripts/generate_cheatsheet.go
2022-01-04 01:46:14 +02:00
package cheatsheet
import (
2019-01-16 19:54:54 +02:00
"fmt"
"log"
"os"
"sort"
"github.com/jesseduffield/lazygit/pkg/app"
"github.com/jesseduffield/lazygit/pkg/config"
2019-03-02 06:11:53 +02:00
"github.com/jesseduffield/lazygit/pkg/gui"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/i18n"
2022-01-04 01:46:14 +02:00
"github.com/jesseduffield/lazygit/pkg/integration"
)
type bindingSection struct {
title string
bindings []*types.Binding
}
2022-01-04 01:46:14 +02:00
func CommandToRun() string {
return "go run scripts/cheatsheet/main.go generate"
}
func GetDir() string {
return integration.GetRootDirectory() + "/docs/keybindings"
}
func generateAtDir(cheatsheetDir string) {
translationSetsByLang := i18n.GetTranslationSets()
mConfig := config.NewDummyAppConfig()
for lang := range translationSetsByLang {
mConfig.GetUserConfig().Gui.Language = lang
2022-01-31 13:11:34 +02:00
mApp, _ := app.NewApp(mConfig)
2022-01-04 01:46:14 +02:00
path := cheatsheetDir + "/Keybindings_" + lang + ".md"
file, err := os.Create(path)
2019-03-22 11:13:48 +02:00
if err != nil {
panic(err)
}
bindingSections := getBindingSections(mApp)
content := formatSections(mApp.Tr, bindingSections)
2022-01-19 12:36:42 +02:00
content = fmt.Sprintf("_This file is auto-generated. To update, make the changes in the "+
"pkg/i18n directory and then run `%s` from the project root._\n\n%s", CommandToRun(), content)
writeString(file, content)
}
}
2022-01-04 01:46:14 +02:00
func Generate() {
generateAtDir(GetDir())
}
func writeString(file *os.File, str string) {
2019-01-16 19:54:54 +02:00
_, err := file.WriteString(str)
if err != nil {
log.Fatal(err)
}
}
2019-03-02 06:11:53 +02:00
func localisedTitle(mApp *app.App, str string) string {
2020-10-04 02:00:48 +02:00
tr := mApp.Tr
contextTitleMap := map[string]string{
"global": tr.GlobalTitle,
"navigation": tr.NavigationTitle,
"branches": tr.BranchesTitle,
"localBranches": tr.LocalBranchesTitle,
"files": tr.FilesTitle,
"status": tr.StatusTitle,
"submodules": tr.SubmodulesTitle,
"subCommits": tr.SubCommitsTitle,
"remoteBranches": tr.RemoteBranchesTitle,
"remotes": tr.RemotesTitle,
"reflogCommits": tr.ReflogCommitsTitle,
"tags": tr.TagsTitle,
"commitFiles": tr.CommitFilesTitle,
"commitMessage": tr.CommitMessageTitle,
"commits": tr.CommitsTitle,
"confirmation": tr.ConfirmationTitle,
"credentials": tr.CredentialsTitle,
"information": tr.InformationTitle,
"main": tr.MainTitle,
"patchBuilding": tr.PatchBuildingTitle,
"merging": tr.MergingTitle,
"normal": tr.NormalTitle,
"staging": tr.StagingTitle,
"menu": tr.MenuTitle,
"search": tr.SearchTitle,
"secondary": tr.SecondaryTitle,
"stash": tr.StashTitle,
2021-10-23 02:25:37 +02:00
"suggestions": tr.SuggestionsCheatsheetTitle,
2021-06-15 20:10:37 +02:00
"extras": tr.ExtrasTitle,
2020-10-04 02:00:48 +02:00
}
title, ok := contextTitleMap[str]
if !ok {
panic(fmt.Sprintf("title not found for %s", str))
}
return title
}
2019-03-02 06:11:53 +02:00
func formatTitle(title string) string {
return fmt.Sprintf("\n## %s\n\n", title)
}
func formatBinding(binding *types.Binding) string {
if binding.Alternative != "" {
return fmt.Sprintf(" <kbd>%s</kbd>: %s (%s)\n", gui.GetKeyDisplay(binding.Key), binding.Description, binding.Alternative)
}
return fmt.Sprintf(" <kbd>%s</kbd>: %s\n", gui.GetKeyDisplay(binding.Key), binding.Description)
2019-03-02 06:11:53 +02:00
}
func getBindingSections(mApp *app.App) []*bindingSection {
bindingSections := []*bindingSection{}
2019-01-16 19:54:54 +02:00
bindings := mApp.Gui.GetInitialKeybindings()
type contextAndViewType struct {
2020-10-01 23:32:48 +02:00
subtitle string
title string
}
contextAndViewBindingMap := map[contextAndViewType][]*types.Binding{}
2020-10-01 23:32:48 +02:00
outer:
for _, binding := range bindings {
2020-10-01 23:32:48 +02:00
if binding.Tag == "navigation" {
key := contextAndViewType{subtitle: "", title: "navigation"}
existing := contextAndViewBindingMap[key]
if existing == nil {
contextAndViewBindingMap[key] = []*types.Binding{binding}
2020-10-01 23:32:48 +02:00
} else {
for _, navBinding := range contextAndViewBindingMap[key] {
if navBinding.Description == binding.Description {
continue outer
}
}
contextAndViewBindingMap[key] = append(contextAndViewBindingMap[key], binding)
}
continue outer
}
contexts := []string{}
if len(binding.Contexts) == 0 {
contexts = append(contexts, "")
} else {
2020-03-09 02:34:10 +02:00
contexts = append(contexts, binding.Contexts...)
2019-01-16 19:54:54 +02:00
}
for _, context := range contexts {
2020-10-01 23:32:48 +02:00
key := contextAndViewType{subtitle: context, title: binding.ViewName}
existing := contextAndViewBindingMap[key]
if existing == nil {
contextAndViewBindingMap[key] = []*types.Binding{binding}
} else {
contextAndViewBindingMap[key] = append(contextAndViewBindingMap[key], binding)
}
2019-01-16 19:54:54 +02:00
}
}
type groupedBindingsType struct {
contextAndView contextAndViewType
bindings []*types.Binding
}
groupedBindings := make([]groupedBindingsType, len(contextAndViewBindingMap))
2019-01-16 19:54:54 +02:00
for contextAndView, contextBindings := range contextAndViewBindingMap {
groupedBindings = append(groupedBindings, groupedBindingsType{contextAndView: contextAndView, bindings: contextBindings})
2019-01-16 19:54:54 +02:00
}
sort.Slice(groupedBindings, func(i, j int) bool {
first := groupedBindings[i].contextAndView
second := groupedBindings[j].contextAndView
2020-10-01 23:32:48 +02:00
if first.title == "" {
return true
}
if second.title == "" {
return false
}
if first.title == "navigation" {
return true
}
2020-10-01 23:32:48 +02:00
if second.title == "navigation" {
return false
}
2020-10-01 23:32:48 +02:00
return first.title < second.title || (first.title == second.title && first.subtitle < second.subtitle)
})
for _, group := range groupedBindings {
contextAndView := group.contextAndView
contextBindings := group.bindings
2020-10-01 23:32:48 +02:00
mApp.Log.Info("viewname: " + contextAndView.title + ", context: " + contextAndView.subtitle)
viewName := contextAndView.title
if viewName == "" {
viewName = "global"
}
translatedView := localisedTitle(mApp, viewName)
var title string
2020-10-01 23:32:48 +02:00
if contextAndView.subtitle == "" {
2020-10-04 02:00:48 +02:00
addendum := " " + mApp.Tr.Panel
2020-10-01 23:32:48 +02:00
if viewName == "global" || viewName == "navigation" {
addendum = ""
}
title = fmt.Sprintf("%s%s", translatedView, addendum)
} else {
2020-10-01 23:32:48 +02:00
translatedContextName := localisedTitle(mApp, contextAndView.subtitle)
2020-10-04 02:00:48 +02:00
title = fmt.Sprintf("%s %s (%s)", translatedView, mApp.Tr.Panel, translatedContextName)
}
2019-11-10 07:33:31 +02:00
for _, binding := range contextBindings {
bindingSections = addBinding(title, bindingSections, binding)
2019-03-02 06:11:53 +02:00
}
}
return bindingSections
}
func addBinding(title string, bindingSections []*bindingSection, binding *types.Binding) []*bindingSection {
if binding.Description == "" && binding.Alternative == "" {
return bindingSections
}
for _, section := range bindingSections {
if title == section.title {
section.bindings = append(section.bindings, binding)
return bindingSections
}
}
section := &bindingSection{
title: title,
bindings: []*types.Binding{binding},
}
return append(bindingSections, section)
}
func formatSections(tr *i18n.TranslationSet, bindingSections []*bindingSection) string {
content := fmt.Sprintf("# Lazygit %s\n", tr.Keybindings)
for _, section := range bindingSections {
content += formatTitle(section.title)
content += "<pre>\n"
for _, binding := range section.bindings {
content += formatBinding(binding)
}
content += "</pre>\n"
}
return content
}