mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-01-08 04:04:22 +02:00
217 lines
6.0 KiB
Go
217 lines
6.0 KiB
Go
// 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:
|
|
// go run scripts/generate_cheatsheet.go
|
|
|
|
package cheatsheet
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
|
|
"github.com/jesseduffield/generics/maps"
|
|
"github.com/jesseduffield/generics/slices"
|
|
"github.com/jesseduffield/lazygit/pkg/app"
|
|
"github.com/jesseduffield/lazygit/pkg/config"
|
|
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
|
"github.com/jesseduffield/lazygit/pkg/i18n"
|
|
"github.com/jesseduffield/lazygit/pkg/integration"
|
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
"github.com/samber/lo"
|
|
)
|
|
|
|
type bindingSection struct {
|
|
title string
|
|
bindings []*types.Binding
|
|
}
|
|
|
|
type header struct {
|
|
// priority decides the order of the headers in the cheatsheet (lower means higher)
|
|
priority int
|
|
title string
|
|
}
|
|
|
|
type headerWithBindings struct {
|
|
header header
|
|
bindings []*types.Binding
|
|
}
|
|
|
|
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
|
|
common, err := app.NewCommon(mConfig)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
mApp, _ := app.NewApp(mConfig, common)
|
|
path := cheatsheetDir + "/Keybindings_" + lang + ".md"
|
|
file, err := os.Create(path)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
bindings := mApp.Gui.GetCheatsheetKeybindings()
|
|
bindingSections := getBindingSections(bindings, mApp.Tr)
|
|
content := formatSections(mApp.Tr, bindingSections)
|
|
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)
|
|
}
|
|
}
|
|
|
|
func Generate() {
|
|
generateAtDir(GetDir())
|
|
}
|
|
|
|
func writeString(file *os.File, str string) {
|
|
_, err := file.WriteString(str)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func localisedTitle(tr *i18n.TranslationSet, str string) string {
|
|
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,
|
|
"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,
|
|
"suggestions": tr.SuggestionsCheatsheetTitle,
|
|
"extras": tr.ExtrasTitle,
|
|
}
|
|
|
|
title, ok := contextTitleMap[str]
|
|
if !ok {
|
|
panic(fmt.Sprintf("title not found for %s", str))
|
|
}
|
|
|
|
return title
|
|
}
|
|
|
|
func getBindingSections(bindings []*types.Binding, tr *i18n.TranslationSet) []*bindingSection {
|
|
bindingsToDisplay := slices.Filter(bindings, func(binding *types.Binding) bool {
|
|
return binding.Description != "" || binding.Alternative != ""
|
|
})
|
|
|
|
bindingsByHeader := utils.MuiltiGroupBy(bindingsToDisplay, func(binding *types.Binding) []header {
|
|
return getHeaders(binding, tr)
|
|
})
|
|
|
|
bindingGroups := maps.MapToSlice(
|
|
bindingsByHeader,
|
|
func(header header, hBindings []*types.Binding) headerWithBindings {
|
|
uniqBindings := lo.UniqBy(hBindings, func(binding *types.Binding) string {
|
|
return binding.Description + keybindings.GetKeyDisplay(binding.Key)
|
|
})
|
|
|
|
return headerWithBindings{
|
|
header: header,
|
|
bindings: uniqBindings,
|
|
}
|
|
},
|
|
)
|
|
|
|
slices.SortFunc(bindingGroups, func(a, b headerWithBindings) bool {
|
|
if a.header.priority != b.header.priority {
|
|
return a.header.priority > b.header.priority
|
|
}
|
|
return a.header.title < b.header.title
|
|
})
|
|
|
|
return slices.Map(bindingGroups, func(hb headerWithBindings) *bindingSection {
|
|
return &bindingSection{
|
|
title: hb.header.title,
|
|
bindings: hb.bindings,
|
|
}
|
|
})
|
|
}
|
|
|
|
// a binding may belong to multiple headers if it is applicable to multiple contexts,
|
|
// for example the copy-to-clipboard binding.
|
|
func getHeaders(binding *types.Binding, tr *i18n.TranslationSet) []header {
|
|
if binding.Tag == "navigation" {
|
|
return []header{{priority: 2, title: localisedTitle(tr, "navigation")}}
|
|
}
|
|
|
|
if binding.ViewName == "" {
|
|
return []header{{priority: 3, title: localisedTitle(tr, "global")}}
|
|
}
|
|
|
|
if len(binding.Contexts) == 0 {
|
|
return []header{}
|
|
}
|
|
|
|
return slices.Map(binding.Contexts, func(context string) header {
|
|
return header{priority: 1, title: localisedTitle(tr, context)}
|
|
})
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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",
|
|
keybindings.GetKeyDisplay(binding.Key),
|
|
binding.Description,
|
|
binding.Alternative,
|
|
)
|
|
}
|
|
return fmt.Sprintf(" <kbd>%s</kbd>: %s\n", keybindings.GetKeyDisplay(binding.Key), binding.Description)
|
|
}
|