mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-05-11 12:25:47 +02:00
add integration test for staging view
This commit is contained in:
parent
99035959a1
commit
ee622d044e
37 changed files with 1102 additions and 0 deletions
|
@ -0,0 +1 @@
|
|||
test
|
0
test/integration/staging/expected/.git_keep/FETCH_HEAD
Normal file
0
test/integration/staging/expected/.git_keep/FETCH_HEAD
Normal file
1
test/integration/staging/expected/.git_keep/HEAD
Normal file
1
test/integration/staging/expected/.git_keep/HEAD
Normal file
|
@ -0,0 +1 @@
|
|||
ref: refs/heads/master
|
10
test/integration/staging/expected/.git_keep/config
Normal file
10
test/integration/staging/expected/.git_keep/config
Normal file
|
@ -0,0 +1,10 @@
|
|||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
||||
ignorecase = true
|
||||
precomposeunicode = true
|
||||
[user]
|
||||
email = CI@example.com
|
||||
name = CI
|
1
test/integration/staging/expected/.git_keep/description
Normal file
1
test/integration/staging/expected/.git_keep/description
Normal file
|
@ -0,0 +1 @@
|
|||
Unnamed repository; edit this file 'description' to name the repository.
|
BIN
test/integration/staging/expected/.git_keep/index
Normal file
BIN
test/integration/staging/expected/.git_keep/index
Normal file
Binary file not shown.
7
test/integration/staging/expected/.git_keep/info/exclude
Normal file
7
test/integration/staging/expected/.git_keep/info/exclude
Normal file
|
@ -0,0 +1,7 @@
|
|||
# git ls-files --others --exclude-from=.git/info/exclude
|
||||
# Lines that start with '#' are comments.
|
||||
# For a project mostly in C, the following would be a good set of
|
||||
# exclude patterns (uncomment them if you want to use them):
|
||||
# *.[oa]
|
||||
# *~
|
||||
.DS_Store
|
2
test/integration/staging/expected/.git_keep/logs/HEAD
Normal file
2
test/integration/staging/expected/.git_keep/logs/HEAD
Normal file
|
@ -0,0 +1,2 @@
|
|||
0000000000000000000000000000000000000000 6806c569c7c063ec7ed3d16da3faa32a1622bb4b CI <CI@example.com> 1642402468 +1100 commit (initial): file1
|
||||
6806c569c7c063ec7ed3d16da3faa32a1622bb4b 4253d2597aec2a480a8e9054250e6b4aa5b76d9e CI <CI@example.com> 1642402495 +1100 commit: test
|
|
@ -0,0 +1,2 @@
|
|||
0000000000000000000000000000000000000000 6806c569c7c063ec7ed3d16da3faa32a1622bb4b CI <CI@example.com> 1642402468 +1100 commit (initial): file1
|
||||
6806c569c7c063ec7ed3d16da3faa32a1622bb4b 4253d2597aec2a480a8e9054250e6b4aa5b76d9e CI <CI@example.com> 1642402495 +1100 commit: test
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,2 @@
|
|||
x<01>ÎA
|
||||
Â0@Q×9Eö‚d’Ì4<C38C>"BW=ÆL:AÁØR#x|{·Ÿ·øemíÑ-d8õ]Õ:̘H"%IYjN„<xª‘P”#c5ïúê–’£‚”ËP-ƒ.aZ8TæàÈ{‘(†?ý¾îvší8Í7ýrÛžz)k»Z è£ó1£=8gŽzLuý“›®ïn~!–9o
|
|
@ -0,0 +1,4 @@
|
|||
xM’±nÜ0†;û)þN·øŒtÉÐN:dêÈÐY¶hK8Yt%ê„ÛúyÂ<I()
|
||||
†Eþ"?þôxÆã—‡O—"G‰FT:ÝÕ„+Yü.^kòm¸£Æ2âFœÏËX®&Zh”"ªç÷sè‰9hºëŸM²µ®óùð!ø¸a§œÏâc†<63>à’àT?
ý¢;e%:dĬˆ-¹èËlëm< jÒ†4
Otj%HŸ¢—Ç\B É<>Â5<C382>^ÞÙáÅ%sD
|
||||
~Ç©d¥ªNp„l”Ê^e4_•VBÏû@]àÌMÏmú4˽sµ¦;¤fDº‘Ži¿ƒ×6@þÜjÓAl7«jˆÌVZ—r°
|
||||
WöiøÉÈzò”tˆÃxÛöpõËf3êœàI=¸RÊÓõG¼ýyÅ5rmF‹Óv3‰(ÒÞvÅ¥uà<75>Æá»npKm‡IÁSþú×
2‹Ã‘¸X¬~s-;«ýYýî2püøVNþFù"Kk0¢ÅÖÐôï‡8Öï
|
|
@ -0,0 +1,2 @@
|
|||
x<01>ÍA
|
||||
Â0Fa×9Åì™I~B"BW=Æ$<24>`¡!R"x|{·<>^émƒ¸ŒÃŒj6N*’BÈ€i䌘W®a¾ä(SR8ýŒW?h^è>/Oûj{ïv+½=H"<Ø#Ntavg='Ãþä®n»‰û¶¹+•
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,2 @@
|
|||
xM’¿nÜ0Æ;û)¾N·øŒNš©@‡L¹:Ëm '‹®D<C2AE>p["O˜')¥4ECÿˆüñ£çÀ3¾<|º<14>8J4¢ÒéF¨&\ÉâWñBX“§hÃå€0¾“7â|^ŒÀr<C380>0ÑB½Q½88¿<38>X˜CÌAÃ=ÿ‡I–£Öu>#>7ì”óY|Ìð\œæOÃEot§¬D‡Œ˜±=ÌF°ÞÆ“ &mHÓðD§VR<56>ô+ú¨qÌ%’Ü)\KÐÇ›#;¼¸dŽHaÂOB6
|
||||
Q<EFBFBD>»¿† ¼Ê8h¬*©%ÖK žàÌMí<4D>}’åÞ†‹ÊÒÕQý2"ÝHGˆ´ßÁkƒÏŸ[Í`:DíBUu‘ÙJëòO=‹+û4<3²Zž’poÛ®~¹ÂlFU<©šWJyú¯þˆ·ß¯¸F®MdqÚn&EÚÛž¸´¼Ó8|Óím©í/)xÊ_ßÕ ³8‰‹Åê7×¢³JŸU랎ÿÂÊ Áß(?"²´#šo
-ÿ΢Õ@
|
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
x=’=ŽÜ0…Sű/Ő4Ţ©‚-’*@Švl±µlŃ–0˛ččgŚér<C3A9>ś0'É“‚YŔ ň‰üřč)č„çç/ź.µ 8I2â<32>ÓMp<4D>p‹_ŐÁ’ĽDî¨;Šâ‡<C3A2>âF<=
o¦Ŕęa˘Łqřâŕü6bV
=1¦»ţ§IV#ë:ź‘w‚Ź+6Éů©ř<C2A9>á#´&8ęĎĂ{ÉŃ/_<>kv(ÎĎW¨mJ]z©)} ]•»dα—k™‡YÖŰx*81ĺ<ĽČ©<C48C>p~•ŹýTC<54>’;»k>^ťŘáÍ%łG gĽf§©f’ŽP¤Ë†ł<E280A0> KÉΰĎ%ôĽŇÎÜx´éĚ÷Î1\hh÷•ÎgDą Ç<>˛ÝŰ<C39D>dĎź[Í`:H<>í‰Ykëňá»K¸şť‡WEćÍKâ»ńtQqmî™ŐĐď‚îa×CRn~?ęŹřűű®QʶžâŘn’R<E28099>´µ
kmt“qřνs+Ü|"xĘ_˙»!fvŘ“V‹ĹŻ®e'Úźéw—Aăă/Z4!ř›äo<C3A4>ZZ<5A>-¶„¦˙ Îéb
|
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
4253d2597aec2a480a8e9054250e6b4aa5b76d9e
|
15
test/integration/staging/expected/one.txt
Normal file
15
test/integration/staging/expected/one.txt
Normal file
|
@ -0,0 +1,15 @@
|
|||
Out there, we've walked quite friendly up to Death, --
|
||||
Sat down and eaten with him, cool and bland, --
|
||||
Pardoned his spilling mess-tins in our hand.
|
||||
We've sniffed the green thick smell of his breath, --
|
||||
Our eyes wept, but our courage did not writhe.
|
||||
He's spat at us with bullets and he's coughed
|
||||
Shrapnel. We sang when he sang aloft,
|
||||
We whistled while he shaved us with his scythe.
|
||||
|
||||
Oh, Death was never enemy of ours!
|
||||
We laughed at him, we leagued with him, old chum.
|
||||
No soldier's paid to kick against His powers.
|
||||
We laughed, — knowing that greater men would come,
|
||||
And greater wars: when each proud fighter brags
|
||||
He wars on Death, for lives; not men, for flags
|
301
test/integration/staging/expected/three.txt
Normal file
301
test/integration/staging/expected/three.txt
Normal file
|
@ -0,0 +1,301 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/loaders"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
// list panel functions
|
||||
|
||||
func (gui *Gui) getSelectednodeNode() *nodetree.nodeNode {
|
||||
selectedLine := gui.State.Panels.nodes.SelectedLineIdx
|
||||
if selectedLine == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return gui.State.FileManager.GetItemAtIndex(selectedLine)
|
||||
return gui.State.nodeManager.GetItemAtIndex(selectedLine)
|
||||
}
|
||||
|
||||
func (gui *Gui) getSelectednode() *models.node {
|
||||
node := gui.getSelectednodeNode()
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
return node.node
|
||||
}
|
||||
|
||||
func (gui *Gui) getSelectedPath() string {
|
||||
node := gui.getSelectednodeNode()
|
||||
if node == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return node.GetPath()
|
||||
}
|
||||
|
||||
func (gui *Gui) filesRenderToMain() error {
|
||||
node := gui.getSelectedFileNode()
|
||||
func (gui *Gui) nodesRenderToMain() error {
|
||||
node := gui.getSelectednodeNode()
|
||||
|
||||
if node == nil {
|
||||
return gui.refreshMainViews(refreshMainOpts{
|
||||
main: &viewUpdateOpts{
|
||||
title: "",
|
||||
task: NewRenderStringTask(gui.Tr.NoChangednodes),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if node.node != nil && node.File.HasInlineMergeConflicts {
|
||||
return gui.renderConflictsFromFilesPanel()
|
||||
}
|
||||
|
||||
cmdObj := gui.Git.WorkingTree.WorktreeFileDiffCmdObj(node, false, !node.GetHasUnstagedChanges() && node.GetHasStagedChanges(), gui.State.IgnoreWhitespaceInDiffView)
|
||||
|
||||
refreshOpts := refreshMainOpts{main: &viewUpdateOpts{
|
||||
title: gui.Tr.UnstagedChanges,
|
||||
task: NewRunPtyTask(cmdObj.GetCmd()),
|
||||
}}
|
||||
|
||||
if node.GetHasUnstagedChanges() {
|
||||
if node.GetHasStagedChanges() {
|
||||
cmdObj := gui.Git.WorkingTree.WorktreeFileDiffCmdObj(node, false, true, gui.State.IgnoreWhitespaceInDiffView)
|
||||
|
||||
refreshOpts.secondary = &viewUpdateOpts{
|
||||
title: gui.Tr.StagedChanges,
|
||||
task: NewRunPtyTask(cmdObj.GetCmd()),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
refreshOpts.main.title = gui.Tr.StagedChanges
|
||||
}
|
||||
|
||||
return gui.refreshMainViews(refreshOpts)
|
||||
}
|
||||
|
||||
func (gui *Gui) refreshFilesAndSubmodules() error {
|
||||
gui.Mutexes.RefreshingFilesMutex.Lock()
|
||||
gui.State.IsRefreshingFiles = true
|
||||
defer func() {
|
||||
gui.State.IsRefreshingFiles = false
|
||||
gui.Mutexes.RefreshingFilesMutex.Unlock()
|
||||
}()
|
||||
|
||||
selectedPath := gui.getSelectedPath()
|
||||
|
||||
if err := gui.refreshStateSubmoduleConfigs(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gui.refreshStateFiles(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gui.OnUIThread(func() error {
|
||||
if err := gui.postRefreshUpdate(gui.State.Contexts.Submodules); err != nil {
|
||||
gui.Log.Error(err)
|
||||
}
|
||||
|
||||
if ContextKey(gui.Views.Files.Context) == FILES_CONTEXT_KEY {
|
||||
// doing this a little custom (as opposed to using gui.postRefreshUpdate) because we handle selecting the file explicitly below
|
||||
if err := gui.State.Contexts.Files.HandleRender(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if gui.currentContext().GetKey() == FILES_CONTEXT_KEY || (gui.g.CurrentView() == gui.Views.Main && ContextKey(gui.g.CurrentView().Context) == MAIN_MERGING_CONTEXT_KEY) {
|
||||
newSelectedPath := gui.getSelectedPath()
|
||||
alreadySelected := selectedPath != "" && newSelectedPath == selectedPath
|
||||
if !alreadySelected {
|
||||
gui.takeOverMergeConflictScrolling()
|
||||
}
|
||||
|
||||
gui.Views.Files.FocusPoint(0, gui.State.Panels.Files.SelectedLineIdx)
|
||||
return gui.filesRenderToMain()
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// specific functions
|
||||
|
||||
func (gui *Gui) stagedFiles() []*models.File {
|
||||
files := gui.State.FileManager.GetAllFiles()
|
||||
result := make([]*models.File, 0)
|
||||
for _, file := range files {
|
||||
if file.HasStagedChanges {
|
||||
result = append(result, file)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (gui *Gui) trackedFiles() []*models.File {
|
||||
files := gui.State.FileManager.GetAllFiles()
|
||||
result := make([]*models.File, 0, len(files))
|
||||
for _, file := range files {
|
||||
if file.Tracked {
|
||||
result = append(result, file)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (gui *Gui) stageSelectedFile() error {
|
||||
file := gui.getSelectedFile()
|
||||
if file == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return gui.Git.WorkingTree.StageFile(file.Name)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleEnterFile() error {
|
||||
return gui.enterFile(OnFocusOpts{ClickedViewName: "", ClickedViewLineIdx: -1})
|
||||
}
|
||||
|
||||
func (gui *Gui) enterFile(opts OnFocusOpts) error {
|
||||
node := gui.getSelectedFileNode()
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if node.File == nil {
|
||||
return gui.handleToggleDirCollapsed()
|
||||
}
|
||||
|
||||
file := node.File
|
||||
|
||||
submoduleConfigs := gui.State.Submodules
|
||||
if file.IsSubmodule(submoduleConfigs) {
|
||||
submoduleConfig := file.SubmoduleConfig(submoduleConfigs)
|
||||
return gui.enterSubmodule(submoduleConfig)
|
||||
}
|
||||
|
||||
if file.HasInlineMergeConflicts {
|
||||
return gui.switchToMerge()
|
||||
}
|
||||
if file.HasMergeConflicts {
|
||||
return gui.createErrorPanel(gui.Tr.FileStagingRequirements)
|
||||
}
|
||||
|
||||
return gui.pushContext(gui.State.Contexts.Staging, opts)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleFilePress() error {
|
||||
node := gui.getSelectedFileNode()
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if node.IsLeaf() {
|
||||
file := node.File
|
||||
|
||||
if file.HasInlineMergeConflicts {
|
||||
return gui.switchToMerge()
|
||||
}
|
||||
|
||||
if node.HasUnstagedChanges {
|
||||
gui.logAction(gui.Tr.Actions.Stagenode)
|
||||
if err := gui.Git.WorkingTree.Stagenode(node.Name); err != nil {
|
||||
return gui.surfaceError(err)
|
||||
}
|
||||
} else {
|
||||
gui.logAction(gui.Tr.Actions.Unstagenode)
|
||||
if err := gui.Git.WorkingTree.UnStagenode(node.Names(), node.Tracked); err != nil {
|
||||
return gui.surfaceError(err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if node.GetHasInlineMergeConflicts() {
|
||||
return gui.createErrorPanel(gui.Tr.ErrStageDirWithInlineMergeConflicts)
|
||||
}
|
||||
|
||||
if node.GetHasUnstagedChanges() {
|
||||
gui.logAction(gui.Tr.Actions.Stagenode)
|
||||
if err := gui.Git.WorkingTree.Stagenode(node.Path); err != nil {
|
||||
return gui.surfaceError(err)
|
||||
}
|
||||
} else {
|
||||
// pretty sure it doesn't matter that we're always passing true here
|
||||
gui.logAction(gui.Tr.Actions.Unstagenode)
|
||||
if err := gui.Git.WorkingTree.UnStagenode([]string{node.Path}, true); err != nil {
|
||||
return gui.surfaceError(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := gui.blah(refreshOptions{scope: []RefreshableView{nodeS}}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.State.Contexts.nodes.HandleFocus()
|
||||
}
|
||||
|
||||
func (gui *Gui) allnodesStaged() bool {
|
||||
for _, node := range gui.State.nodeManager.GetAllnodes() {
|
||||
if node.HasUnstagedChanges {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (gui *Gui) onFocusnode() error {
|
||||
gui.takeOverMergeConflictScrolling()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) handleStageAll() error {
|
||||
var err error
|
||||
if gui.allnodesStaged() {
|
||||
gui.logAction(gui.Tr.Actions.UnstageAllnodes)
|
||||
err = gui.Git.WorkingTree.UnstageAll()
|
||||
} else {
|
||||
gui.logAction(gui.Tr.Actions.StageAllnodes)
|
||||
err = gui.Git.WorkingTree.StageAll()
|
||||
}
|
||||
if err != nil {
|
||||
_ = gui.surfaceError(err)
|
||||
}
|
||||
|
||||
if err := gui.blah(refreshOptions{scope: []RefreshableView{nodeS}}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.State.Contexts.nodes.HandleFocus()
|
||||
}
|
||||
|
||||
func (gui *Gui) handleIgnorenode() error {
|
||||
node := gui.getSelectednodeNode()
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if node.GetPath() == ".gitignore" {
|
||||
return gui.createErrorPanel("Cannot ignore .gitignore")
|
||||
}
|
||||
|
||||
unstagenodes := func() error {
|
||||
return node.ForEachnode(func(node *models.node) error {
|
||||
if node.HasStagedChanges {
|
||||
if err := gui.Git.WorkingTree.UnStagenode(node.Names(), node.Tracked); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
33
test/integration/staging/expected/two.txt
Normal file
33
test/integration/staging/expected/two.txt
Normal file
|
@ -0,0 +1,33 @@
|
|||
type createMenuOptions struct {
|
||||
showCancel bool
|
||||
}
|
||||
|
||||
func (gui *Gui) createMenu(title string, items []*menuItem, createMenuOptions createMenuOptions) error {
|
||||
if createMenuOptions.showCancel {
|
||||
// this is mutative but I'm okay with that for now
|
||||
items = app(items, &menuItem{
|
||||
d: []string{gui.Tr.LcCancel},
|
||||
onPress: func() error {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
gui.State.MenuItems = items
|
||||
|
||||
stringArrays := make([][]string, len(items))
|
||||
for i, items := range items {
|
||||
if items.opensMenu && item.displayStrings != nil {
|
||||
return errors.New("Message for the developer of this app: you've set opensMenu with displaystrings on the menu panel. Bad developer!. Apologies, user")
|
||||
}
|
||||
|
||||
if item.displayStrings == nil {
|
||||
styledStr := item.displayString
|
||||
if item.opensMenu {
|
||||
styledStr = opensMenuStyle(styledStr)
|
||||
}
|
||||
stringArrays[i] = []string{styledStr}
|
||||
} else {
|
||||
stringArrays[i] = item.displayStrings
|
||||
}
|
||||
}
|
15
test/integration/staging/files/one.txt
Normal file
15
test/integration/staging/files/one.txt
Normal file
|
@ -0,0 +1,15 @@
|
|||
Out there, we've walked quite friendly up to Death, --
|
||||
Sat down and eaten with him, cool and bland, --
|
||||
Pardoned his spilling mess-tins in our hand.
|
||||
We've sniffed the green thick odour of his breath, --
|
||||
Our eyes wept, but our courage didn't writhe.
|
||||
He's spat at us with bullets and he's coughed
|
||||
Shrapnel. We chorused when he sang aloft,
|
||||
We whistled while he shaved us with his scythe.
|
||||
|
||||
Oh, Death was never enemy of ours!
|
||||
We laughed at him, we leagued with him, old chum.
|
||||
No soldier's paid to kick against His powers.
|
||||
We laughed, — knowing that better men would come,
|
||||
And greater wars: when each proud fighter brags
|
||||
He wars on Death, for lives; not men, for flags
|
15
test/integration/staging/files/one_new.txt
Normal file
15
test/integration/staging/files/one_new.txt
Normal file
|
@ -0,0 +1,15 @@
|
|||
Out there, we've walked quite friendly up to Death, --
|
||||
Sat down and eaten with him, cool and bland, --
|
||||
Pardoned his spilling mess-tins in our hand.
|
||||
We've sniffed the green thick smell of his breath, --
|
||||
Our eyes wept, but our courage did not writhe.
|
||||
He's spat at us with bullets and he's coughed
|
||||
Shrapnel. We sang when he sang aloft,
|
||||
We whistled while he shaved us with his scythe.
|
||||
|
||||
Oh, Death was never enemy of ours!
|
||||
We laughed at him, we leagued with him, old chum.
|
||||
No soldier's paid to kick against His powers.
|
||||
We laughed, — knowing that greater men would come,
|
||||
And greater wars: when each proud fighter brags
|
||||
He wars on Death, for lives; not men, for flags
|
300
test/integration/staging/files/three.txt
Normal file
300
test/integration/staging/files/three.txt
Normal file
|
@ -0,0 +1,300 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/loaders"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/filetree"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
// list panel functions
|
||||
|
||||
func (gui *Gui) getSelectedFileNode() *filetree.FileNode {
|
||||
selectedLine := gui.State.Panels.Files.SelectedLineIdx
|
||||
if selectedLine == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return gui.State.FileManager.GetItemAtIndex(selectedLine)
|
||||
}
|
||||
|
||||
func (gui *Gui) getSelectedFile() *models.File {
|
||||
node := gui.getSelectedFileNode()
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
return node.File
|
||||
}
|
||||
|
||||
func (gui *Gui) getSelectedPath() string {
|
||||
node := gui.getSelectedFileNode()
|
||||
if node == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return node.GetPath()
|
||||
}
|
||||
|
||||
func (gui *Gui) filesRenderToMain() error {
|
||||
node := gui.getSelectedFileNode()
|
||||
|
||||
if node == nil {
|
||||
return gui.refreshMainViews(refreshMainOpts{
|
||||
main: &viewUpdateOpts{
|
||||
title: "",
|
||||
task: NewRenderStringTask(gui.Tr.NoChangedFiles),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if node.File != nil && node.File.HasInlineMergeConflicts {
|
||||
return gui.renderConflictsFromFilesPanel()
|
||||
}
|
||||
|
||||
cmdObj := gui.Git.WorkingTree.WorktreeFileDiffCmdObj(node, false, !node.GetHasUnstagedChanges() && node.GetHasStagedChanges(), gui.State.IgnoreWhitespaceInDiffView)
|
||||
|
||||
refreshOpts := refreshMainOpts{main: &viewUpdateOpts{
|
||||
title: gui.Tr.UnstagedChanges,
|
||||
task: NewRunPtyTask(cmdObj.GetCmd()),
|
||||
}}
|
||||
|
||||
if node.GetHasUnstagedChanges() {
|
||||
if node.GetHasStagedChanges() {
|
||||
cmdObj := gui.Git.WorkingTree.WorktreeFileDiffCmdObj(node, false, true, gui.State.IgnoreWhitespaceInDiffView)
|
||||
|
||||
refreshOpts.secondary = &viewUpdateOpts{
|
||||
title: gui.Tr.StagedChanges,
|
||||
task: NewRunPtyTask(cmdObj.GetCmd()),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
refreshOpts.main.title = gui.Tr.StagedChanges
|
||||
}
|
||||
|
||||
return gui.refreshMainViews(refreshOpts)
|
||||
}
|
||||
|
||||
func (gui *Gui) refreshFilesAndSubmodules() error {
|
||||
gui.Mutexes.RefreshingFilesMutex.Lock()
|
||||
gui.State.IsRefreshingFiles = true
|
||||
defer func() {
|
||||
gui.State.IsRefreshingFiles = false
|
||||
gui.Mutexes.RefreshingFilesMutex.Unlock()
|
||||
}()
|
||||
|
||||
selectedPath := gui.getSelectedPath()
|
||||
|
||||
if err := gui.refreshStateSubmoduleConfigs(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gui.refreshStateFiles(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gui.OnUIThread(func() error {
|
||||
if err := gui.postRefreshUpdate(gui.State.Contexts.Submodules); err != nil {
|
||||
gui.Log.Error(err)
|
||||
}
|
||||
|
||||
if ContextKey(gui.Views.Files.Context) == FILES_CONTEXT_KEY {
|
||||
// doing this a little custom (as opposed to using gui.postRefreshUpdate) because we handle selecting the file explicitly below
|
||||
if err := gui.State.Contexts.Files.HandleRender(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if gui.currentContext().GetKey() == FILES_CONTEXT_KEY || (gui.g.CurrentView() == gui.Views.Main && ContextKey(gui.g.CurrentView().Context) == MAIN_MERGING_CONTEXT_KEY) {
|
||||
newSelectedPath := gui.getSelectedPath()
|
||||
alreadySelected := selectedPath != "" && newSelectedPath == selectedPath
|
||||
if !alreadySelected {
|
||||
gui.takeOverMergeConflictScrolling()
|
||||
}
|
||||
|
||||
gui.Views.Files.FocusPoint(0, gui.State.Panels.Files.SelectedLineIdx)
|
||||
return gui.filesRenderToMain()
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// specific functions
|
||||
|
||||
func (gui *Gui) stagedFiles() []*models.File {
|
||||
files := gui.State.FileManager.GetAllFiles()
|
||||
result := make([]*models.File, 0)
|
||||
for _, file := range files {
|
||||
if file.HasStagedChanges {
|
||||
result = append(result, file)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (gui *Gui) trackedFiles() []*models.File {
|
||||
files := gui.State.FileManager.GetAllFiles()
|
||||
result := make([]*models.File, 0, len(files))
|
||||
for _, file := range files {
|
||||
if file.Tracked {
|
||||
result = append(result, file)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (gui *Gui) stageSelectedFile() error {
|
||||
file := gui.getSelectedFile()
|
||||
if file == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return gui.Git.WorkingTree.StageFile(file.Name)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleEnterFile() error {
|
||||
return gui.enterFile(OnFocusOpts{ClickedViewName: "", ClickedViewLineIdx: -1})
|
||||
}
|
||||
|
||||
func (gui *Gui) enterFile(opts OnFocusOpts) error {
|
||||
node := gui.getSelectedFileNode()
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if node.File == nil {
|
||||
return gui.handleToggleDirCollapsed()
|
||||
}
|
||||
|
||||
file := node.File
|
||||
|
||||
submoduleConfigs := gui.State.Submodules
|
||||
if file.IsSubmodule(submoduleConfigs) {
|
||||
submoduleConfig := file.SubmoduleConfig(submoduleConfigs)
|
||||
return gui.enterSubmodule(submoduleConfig)
|
||||
}
|
||||
|
||||
if file.HasInlineMergeConflicts {
|
||||
return gui.switchToMerge()
|
||||
}
|
||||
if file.HasMergeConflicts {
|
||||
return gui.createErrorPanel(gui.Tr.FileStagingRequirements)
|
||||
}
|
||||
|
||||
return gui.pushContext(gui.State.Contexts.Staging, opts)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleFilePress() error {
|
||||
node := gui.getSelectedFileNode()
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if node.IsLeaf() {
|
||||
file := node.File
|
||||
|
||||
if file.HasInlineMergeConflicts {
|
||||
return gui.switchToMerge()
|
||||
}
|
||||
|
||||
if file.HasUnstagedChanges {
|
||||
gui.logAction(gui.Tr.Actions.StageFile)
|
||||
if err := gui.Git.WorkingTree.StageFile(file.Name); err != nil {
|
||||
return gui.surfaceError(err)
|
||||
}
|
||||
} else {
|
||||
gui.logAction(gui.Tr.Actions.UnstageFile)
|
||||
if err := gui.Git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil {
|
||||
return gui.surfaceError(err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if any files within have inline merge conflicts we can't stage or unstage,
|
||||
// or it'll end up with those >>>>>> lines actually staged
|
||||
if node.GetHasInlineMergeConflicts() {
|
||||
return gui.createErrorPanel(gui.Tr.ErrStageDirWithInlineMergeConflicts)
|
||||
}
|
||||
|
||||
if node.GetHasUnstagedChanges() {
|
||||
gui.logAction(gui.Tr.Actions.StageFile)
|
||||
if err := gui.Git.WorkingTree.StageFile(node.Path); err != nil {
|
||||
return gui.surfaceError(err)
|
||||
}
|
||||
} else {
|
||||
// pretty sure it doesn't matter that we're always passing true here
|
||||
gui.logAction(gui.Tr.Actions.UnstageFile)
|
||||
if err := gui.Git.WorkingTree.UnStageFile([]string{node.Path}, true); err != nil {
|
||||
return gui.surfaceError(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.State.Contexts.Files.HandleFocus()
|
||||
}
|
||||
|
||||
func (gui *Gui) allFilesStaged() bool {
|
||||
for _, file := range gui.State.FileManager.GetAllFiles() {
|
||||
if file.HasUnstagedChanges {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (gui *Gui) onFocusFile() error {
|
||||
gui.takeOverMergeConflictScrolling()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) handleStageAll() error {
|
||||
var err error
|
||||
if gui.allFilesStaged() {
|
||||
gui.logAction(gui.Tr.Actions.UnstageAllFiles)
|
||||
err = gui.Git.WorkingTree.UnstageAll()
|
||||
} else {
|
||||
gui.logAction(gui.Tr.Actions.StageAllFiles)
|
||||
err = gui.Git.WorkingTree.StageAll()
|
||||
}
|
||||
if err != nil {
|
||||
_ = gui.surfaceError(err)
|
||||
}
|
||||
|
||||
if err := gui.refreshSidePanels(refreshOptions{scope: []RefreshableView{FILES}}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.State.Contexts.Files.HandleFocus()
|
||||
}
|
||||
|
||||
func (gui *Gui) handleIgnoreFile() error {
|
||||
node := gui.getSelectedFileNode()
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if node.GetPath() == ".gitignore" {
|
||||
return gui.createErrorPanel("Cannot ignore .gitignore")
|
||||
}
|
||||
|
||||
unstageFiles := func() error {
|
||||
return node.ForEachFile(func(file *models.File) error {
|
||||
if file.HasStagedChanges {
|
||||
if err := gui.Git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
298
test/integration/staging/files/three_new.txt
Normal file
298
test/integration/staging/files/three_new.txt
Normal file
|
@ -0,0 +1,298 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/loaders"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/nodetree"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
)
|
||||
|
||||
// list panel functions
|
||||
|
||||
func (gui *Gui) getSelectednodeNode() *nodetree.nodeNode {
|
||||
selectedLine := gui.State.Panels.nodes.SelectedLineIdx
|
||||
if selectedLine == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return gui.State.nodeManager.GetItemAtIndex(selectedLine)
|
||||
}
|
||||
|
||||
func (gui *Gui) getSelectednode() *models.node {
|
||||
node := gui.getSelectednodeNode()
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
return node.node
|
||||
}
|
||||
|
||||
func (gui *Gui) getSelectedPath() string {
|
||||
node := gui.getSelectednodeNode()
|
||||
if node == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return node.GetPath()
|
||||
}
|
||||
|
||||
func (gui *Gui) nodesRenderToMain() error {
|
||||
node := gui.getSelectednodeNode()
|
||||
|
||||
if node == nil {
|
||||
return gui.refreshMainViews(refreshMainOpts{
|
||||
main: &viewUpdateOpts{
|
||||
title: "",
|
||||
task: NewRenderStringTask(gui.Tr.NoChangednodes),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if node.node != nil && node.File.HasInlineMergeConflicts {
|
||||
return gui.renderConflictsFromFilesPanel()
|
||||
}
|
||||
|
||||
cmdObj := gui.Git.WorkingTree.WorktreeFileDiffCmdObj(node, false, !node.GetHasUnstagedChanges() && node.GetHasStagedChanges(), gui.State.IgnoreWhitespaceInDiffView)
|
||||
|
||||
refreshOpts := refreshMainOpts{main: &viewUpdateOpts{
|
||||
title: gui.Tr.UnstagedChanges,
|
||||
task: NewRunPtyTask(cmdObj.GetCmd()),
|
||||
}}
|
||||
|
||||
if node.GetHasUnstagedChanges() {
|
||||
if node.GetHasStagedChanges() {
|
||||
cmdObj := gui.Git.WorkingTree.WorktreeFileDiffCmdObj(node, false, true, gui.State.IgnoreWhitespaceInDiffView)
|
||||
|
||||
refreshOpts.secondary = &viewUpdateOpts{
|
||||
title: gui.Tr.StagedChanges,
|
||||
task: NewRunPtyTask(cmdObj.GetCmd()),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
refreshOpts.main.title = gui.Tr.StagedChanges
|
||||
}
|
||||
|
||||
return gui.refreshMainViews(refreshOpts)
|
||||
}
|
||||
|
||||
func (gui *Gui) refreshFilesAndSubmodules() error {
|
||||
gui.Mutexes.RefreshingFilesMutex.Lock()
|
||||
gui.State.IsRefreshingFiles = true
|
||||
defer func() {
|
||||
gui.State.IsRefreshingFiles = false
|
||||
gui.Mutexes.RefreshingFilesMutex.Unlock()
|
||||
}()
|
||||
|
||||
selectedPath := gui.getSelectedPath()
|
||||
|
||||
if err := gui.refreshStateSubmoduleConfigs(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := gui.refreshStateFiles(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gui.OnUIThread(func() error {
|
||||
if err := gui.postRefreshUpdate(gui.State.Contexts.Submodules); err != nil {
|
||||
gui.Log.Error(err)
|
||||
}
|
||||
|
||||
if ContextKey(gui.Views.Files.Context) == FILES_CONTEXT_KEY {
|
||||
// doing this a little custom (as opposed to using gui.postRefreshUpdate) because we handle selecting the file explicitly below
|
||||
if err := gui.State.Contexts.Files.HandleRender(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if gui.currentContext().GetKey() == FILES_CONTEXT_KEY || (gui.g.CurrentView() == gui.Views.Main && ContextKey(gui.g.CurrentView().Context) == MAIN_MERGING_CONTEXT_KEY) {
|
||||
newSelectedPath := gui.getSelectedPath()
|
||||
alreadySelected := selectedPath != "" && newSelectedPath == selectedPath
|
||||
if !alreadySelected {
|
||||
gui.takeOverMergeConflictScrolling()
|
||||
}
|
||||
|
||||
gui.Views.Files.FocusPoint(0, gui.State.Panels.Files.SelectedLineIdx)
|
||||
return gui.filesRenderToMain()
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// specific functions
|
||||
|
||||
func (gui *Gui) stagedFiles() []*models.File {
|
||||
files := gui.State.FileManager.GetAllFiles()
|
||||
result := make([]*models.File, 0)
|
||||
for _, file := range files {
|
||||
if file.HasStagedChanges {
|
||||
result = append(result, file)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (gui *Gui) trackedFiles() []*models.File {
|
||||
files := gui.State.FileManager.GetAllFiles()
|
||||
result := make([]*models.File, 0, len(files))
|
||||
for _, file := range files {
|
||||
if file.Tracked {
|
||||
result = append(result, file)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (gui *Gui) stageSelectedFile() error {
|
||||
file := gui.getSelectedFile()
|
||||
if file == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return gui.Git.WorkingTree.StageFile(file.Name)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleEnterFile() error {
|
||||
return gui.enterFile(OnFocusOpts{ClickedViewName: "", ClickedViewLineIdx: -1})
|
||||
}
|
||||
|
||||
func (gui *Gui) enterFile(opts OnFocusOpts) error {
|
||||
node := gui.getSelectedFileNode()
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if node.File == nil {
|
||||
return gui.handleToggleDirCollapsed()
|
||||
}
|
||||
|
||||
file := node.File
|
||||
|
||||
submoduleConfigs := gui.State.Submodules
|
||||
if file.IsSubmodule(submoduleConfigs) {
|
||||
submoduleConfig := file.SubmoduleConfig(submoduleConfigs)
|
||||
return gui.enterSubmodule(submoduleConfig)
|
||||
}
|
||||
|
||||
if file.HasInlineMergeConflicts {
|
||||
return gui.switchToMerge()
|
||||
}
|
||||
if file.HasMergeConflicts {
|
||||
return gui.createErrorPanel(gui.Tr.FileStagingRequirements)
|
||||
}
|
||||
|
||||
return gui.pushContext(gui.State.Contexts.Staging, opts)
|
||||
}
|
||||
|
||||
func (gui *Gui) handleFilePress() error {
|
||||
node := gui.getSelectedFileNode()
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if node.IsLeaf() {
|
||||
file := node.File
|
||||
|
||||
if file.HasInlineMergeConflicts {
|
||||
return gui.switchToMerge()
|
||||
}
|
||||
|
||||
if node.HasUnstagedChanges {
|
||||
gui.logAction(gui.Tr.Actions.Stagenode)
|
||||
if err := gui.Git.WorkingTree.Stagenode(node.Name); err != nil {
|
||||
return gui.surfaceError(err)
|
||||
}
|
||||
} else {
|
||||
gui.logAction(gui.Tr.Actions.Unstagenode)
|
||||
if err := gui.Git.WorkingTree.UnStagenode(node.Names(), node.Tracked); err != nil {
|
||||
return gui.surfaceError(err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if node.GetHasInlineMergeConflicts() {
|
||||
return gui.createErrorPanel(gui.Tr.ErrStageDirWithInlineMergeConflicts)
|
||||
}
|
||||
|
||||
if node.GetHasUnstagedChanges() {
|
||||
gui.logAction(gui.Tr.Actions.Stagenode)
|
||||
if err := gui.Git.WorkingTree.Stagenode(node.Path); err != nil {
|
||||
return gui.surfaceError(err)
|
||||
}
|
||||
} else {
|
||||
// pretty sure it doesn't matter that we're always passing true here
|
||||
gui.logAction(gui.Tr.Actions.Unstagenode)
|
||||
if err := gui.Git.WorkingTree.UnStagenode([]string{node.Path}, true); err != nil {
|
||||
return gui.surfaceError(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := gui.blah(refreshOptions{scope: []RefreshableView{nodeS}}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.State.Contexts.nodes.HandleFocus()
|
||||
}
|
||||
|
||||
func (gui *Gui) allnodesStaged() bool {
|
||||
for _, node := range gui.State.nodeManager.GetAllnodes() {
|
||||
if node.HasUnstagedChanges {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (gui *Gui) onFocusnode() error {
|
||||
gui.takeOverMergeConflictScrolling()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gui *Gui) handleStageAll() error {
|
||||
var err error
|
||||
if gui.allnodesStaged() {
|
||||
gui.logAction(gui.Tr.Actions.UnstageAllnodes)
|
||||
err = gui.Git.WorkingTree.UnstageAll()
|
||||
} else {
|
||||
gui.logAction(gui.Tr.Actions.StageAllnodes)
|
||||
err = gui.Git.WorkingTree.StageAll()
|
||||
}
|
||||
if err != nil {
|
||||
_ = gui.surfaceError(err)
|
||||
}
|
||||
|
||||
if err := gui.blah(refreshOptions{scope: []RefreshableView{nodeS}}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return gui.State.Contexts.nodes.HandleFocus()
|
||||
}
|
||||
|
||||
func (gui *Gui) handleIgnorenode() error {
|
||||
node := gui.getSelectednodeNode()
|
||||
if node == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if node.GetPath() == ".gitignore" {
|
||||
return gui.createErrorPanel("Cannot ignore .gitignore")
|
||||
}
|
||||
|
||||
unstagenodes := func() error {
|
||||
return node.ForEachnode(func(node *models.node) error {
|
||||
if node.HasStagedChanges {
|
||||
if err := gui.Git.WorkingTree.UnStagenode(node.Names(), node.Tracked); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
33
test/integration/staging/files/two.txt
Normal file
33
test/integration/staging/files/two.txt
Normal file
|
@ -0,0 +1,33 @@
|
|||
type createMenuOptions struct {
|
||||
showCancel bool
|
||||
}
|
||||
|
||||
func (gui *Gui) createMenu(title string, items []*menuItem, createMenuOptions createMenuOptions) error {
|
||||
if createMenuOptions.showCancel {
|
||||
// this is mutative but I'm okay with that for now
|
||||
items = append(items, &menuItem{
|
||||
displayStrings: []string{gui.Tr.LcCancel},
|
||||
onPress: func() error {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
gui.State.MenuItems = items
|
||||
|
||||
stringArrays := make([][]string, len(items))
|
||||
for i, item := range items {
|
||||
if item.opensMenu && item.displayStrings != nil {
|
||||
return errors.New("Message for the developer of this app: you've set opensMenu with displaystrings on the menu panel. Bad developer!. Apologies, user")
|
||||
}
|
||||
|
||||
if item.displayStrings == nil {
|
||||
styledStr := item.displayString
|
||||
if item.opensMenu {
|
||||
styledStr = opensMenuStyle(styledStr)
|
||||
}
|
||||
stringArrays[i] = []string{styledStr}
|
||||
} else {
|
||||
stringArrays[i] = item.displayStrings
|
||||
}
|
||||
}
|
33
test/integration/staging/files/two_new.txt
Normal file
33
test/integration/staging/files/two_new.txt
Normal file
|
@ -0,0 +1,33 @@
|
|||
type createMenuOptions struct {
|
||||
showCancel bool
|
||||
}
|
||||
|
||||
func (gui *Gui) createMenu(title string, items []*menuItem, createMenuOptions createMenuOptions) error {
|
||||
if createMenuOptions.showCancel {
|
||||
// this is mutative but I'm okay with that for now
|
||||
items = app(items, &menuItem{
|
||||
d: []string{gui.Tr.LcCancel},
|
||||
onPress: func() error {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
gui.State.MenuItems = items
|
||||
|
||||
stringArrays := make([][]string, len(items))
|
||||
for i, items := range items {
|
||||
if items.opensMenu && item.displayStrings != nil {
|
||||
return errors.New("Message for the developer of this app: you've set opensMenu with displaystrings on the menu panel. Bad developer!. Apologies, user")
|
||||
}
|
||||
|
||||
if item.displayStrings == nil {
|
||||
styledStr := item.displayString
|
||||
if item.opensMenu {
|
||||
styledStr = opensMenuStyle(styledStr)
|
||||
}
|
||||
stringArrays[0] = []str0ng{styledStr}
|
||||
} else {
|
||||
str0ngArrays[0] = item.displayStrings
|
||||
}
|
||||
}
|
1
test/integration/staging/recording.json
Normal file
1
test/integration/staging/recording.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"KeyEvents":[{"Timestamp":671,"Mod":0,"Key":13,"Ch":13},{"Timestamp":1095,"Mod":0,"Key":256,"Ch":32},{"Timestamp":1447,"Mod":0,"Key":256,"Ch":32},{"Timestamp":2608,"Mod":0,"Key":258,"Ch":0},{"Timestamp":2743,"Mod":0,"Key":258,"Ch":0},{"Timestamp":2973,"Mod":0,"Key":256,"Ch":118},{"Timestamp":3078,"Mod":0,"Key":258,"Ch":0},{"Timestamp":3215,"Mod":0,"Key":258,"Ch":0},{"Timestamp":3415,"Mod":0,"Key":256,"Ch":32},{"Timestamp":3920,"Mod":0,"Key":9,"Ch":9},{"Timestamp":4287,"Mod":0,"Key":257,"Ch":0},{"Timestamp":4431,"Mod":0,"Key":257,"Ch":0},{"Timestamp":4559,"Mod":0,"Key":257,"Ch":0},{"Timestamp":4848,"Mod":0,"Key":256,"Ch":32},{"Timestamp":5774,"Mod":0,"Key":9,"Ch":9},{"Timestamp":6031,"Mod":0,"Key":258,"Ch":0},{"Timestamp":6294,"Mod":0,"Key":257,"Ch":0},{"Timestamp":6374,"Mod":0,"Key":256,"Ch":118},{"Timestamp":6463,"Mod":0,"Key":258,"Ch":0},{"Timestamp":6591,"Mod":0,"Key":258,"Ch":0},{"Timestamp":6711,"Mod":0,"Key":256,"Ch":32},{"Timestamp":7274,"Mod":0,"Key":27,"Ch":0},{"Timestamp":7591,"Mod":0,"Key":258,"Ch":0},{"Timestamp":7968,"Mod":0,"Key":13,"Ch":13},{"Timestamp":8735,"Mod":0,"Key":256,"Ch":97},{"Timestamp":9039,"Mod":0,"Key":256,"Ch":32},{"Timestamp":9327,"Mod":0,"Key":258,"Ch":0},{"Timestamp":9478,"Mod":0,"Key":258,"Ch":0},{"Timestamp":9815,"Mod":0,"Key":256,"Ch":32},{"Timestamp":10439,"Mod":0,"Key":9,"Ch":9},{"Timestamp":11383,"Mod":0,"Key":256,"Ch":97},{"Timestamp":12095,"Mod":0,"Key":256,"Ch":97},{"Timestamp":12319,"Mod":0,"Key":257,"Ch":0},{"Timestamp":13039,"Mod":0,"Key":256,"Ch":32},{"Timestamp":14109,"Mod":0,"Key":27,"Ch":0},{"Timestamp":15119,"Mod":0,"Key":13,"Ch":13},{"Timestamp":15543,"Mod":0,"Key":256,"Ch":100},{"Timestamp":15855,"Mod":0,"Key":13,"Ch":13},{"Timestamp":16183,"Mod":0,"Key":256,"Ch":100},{"Timestamp":16415,"Mod":0,"Key":13,"Ch":13},{"Timestamp":16832,"Mod":0,"Key":258,"Ch":0},{"Timestamp":17150,"Mod":0,"Key":258,"Ch":0},{"Timestamp":17519,"Mod":0,"Key":256,"Ch":118},{"Timestamp":17654,"Mod":0,"Key":258,"Ch":0},{"Timestamp":17784,"Mod":0,"Key":258,"Ch":0},{"Timestamp":17903,"Mod":0,"Key":258,"Ch":0},{"Timestamp":18015,"Mod":0,"Key":258,"Ch":0},{"Timestamp":18150,"Mod":0,"Key":258,"Ch":0},{"Timestamp":18272,"Mod":0,"Key":258,"Ch":0},{"Timestamp":18567,"Mod":0,"Key":256,"Ch":100},{"Timestamp":18759,"Mod":0,"Key":13,"Ch":13},{"Timestamp":19254,"Mod":0,"Key":258,"Ch":0},{"Timestamp":19736,"Mod":0,"Key":259,"Ch":0},{"Timestamp":20358,"Mod":0,"Key":256,"Ch":100},{"Timestamp":20552,"Mod":0,"Key":13,"Ch":13},{"Timestamp":20871,"Mod":0,"Key":256,"Ch":100},{"Timestamp":20991,"Mod":0,"Key":13,"Ch":13},{"Timestamp":21433,"Mod":0,"Key":27,"Ch":0},{"Timestamp":21647,"Mod":0,"Key":258,"Ch":0},{"Timestamp":21943,"Mod":0,"Key":13,"Ch":13},{"Timestamp":22663,"Mod":0,"Key":256,"Ch":97},{"Timestamp":23207,"Mod":0,"Key":258,"Ch":0},{"Timestamp":23383,"Mod":0,"Key":258,"Ch":0},{"Timestamp":24039,"Mod":0,"Key":256,"Ch":100},{"Timestamp":24391,"Mod":0,"Key":13,"Ch":13},{"Timestamp":25141,"Mod":0,"Key":27,"Ch":0},{"Timestamp":25695,"Mod":0,"Key":256,"Ch":99},{"Timestamp":25959,"Mod":0,"Key":256,"Ch":116},{"Timestamp":26007,"Mod":0,"Key":256,"Ch":101},{"Timestamp":26191,"Mod":0,"Key":256,"Ch":115},{"Timestamp":26214,"Mod":0,"Key":256,"Ch":116},{"Timestamp":26464,"Mod":0,"Key":13,"Ch":13},{"Timestamp":27367,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":272,"Height":74}]}
|
18
test/integration/staging/setup.sh
Normal file
18
test/integration/staging/setup.sh
Normal file
|
@ -0,0 +1,18 @@
|
|||
#!/bin/sh
|
||||
|
||||
cd $1
|
||||
|
||||
git init
|
||||
|
||||
git config user.email "CI@example.com"
|
||||
git config user.name "CI"
|
||||
|
||||
cp ../files/one.txt one.txt
|
||||
cp ../files/two.txt two.txt
|
||||
cp ../files/three.txt three.txt
|
||||
git add .
|
||||
git commit -am file1
|
||||
|
||||
cp ../files/one_new.txt one.txt
|
||||
cp ../files/two_new.txt two.txt
|
||||
cp ../files/three_new.txt three.txt
|
4
test/integration/staging/test.json
Normal file
4
test/integration/staging/test.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"description": "Staging a file line-by-line",
|
||||
"speed": 20
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue