Skip to content

Commit f7295a9

Browse files
committed
Add a "Content of selected file" entry to the copy menu for commit files
This is useful for copying the entire content of the selected file as it was at the selected commit. We only add it to the commit files panel; it is not needed in the files panel, because there you can simply press "e" to edit the file.
1 parent 357c046 commit f7295a9

File tree

4 files changed

+74
-3
lines changed

4 files changed

+74
-3
lines changed

pkg/commands/git_commands/commit.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,13 @@ func (self *CommitCommands) ShowCmdObj(hash string, filterPath string) oscommand
279279
return self.cmd.New(cmdArgs).DontLog()
280280
}
281281

282+
func (self *CommitCommands) ShowFileContentCmdObj(hash string, filePath string) oscommands.ICmdObj {
283+
cmdArgs := NewGitCmd("show").
284+
Arg(fmt.Sprintf("%s:%s", hash, filePath)).
285+
ToArgv()
286+
return self.cmd.New(cmdArgs).DontLog()
287+
}
288+
282289
// Revert reverts the selected commit by hash
283290
func (self *CommitCommands) Revert(hash string) error {
284291
cmdArgs := NewGitCmd("revert").Arg(hash).ToArgv()

pkg/gui/controllers/commits_files_controller.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,16 @@ func (self *CommitFilesController) copyDiffToClipboard(path string, toastMessage
203203
return nil
204204
}
205205

206+
func (self *CommitFilesController) copyFileContentToClipboard(path string) error {
207+
_, to := self.context().GetFromAndToForDiff()
208+
cmdObj := self.c.Git().Commit.ShowFileContentCmdObj(to, path)
209+
diff, err := cmdObj.RunWithOutput()
210+
if err != nil {
211+
return err
212+
}
213+
return self.c.OS().CopyToClipboard(diff)
214+
}
215+
206216
func (self *CommitFilesController) openCopyMenu() error {
207217
node := self.context().GetSelected()
208218

@@ -246,6 +256,27 @@ func (self *CommitFilesController) openCopyMenu() error {
246256
DisabledReason: self.require(self.itemsSelected())(),
247257
Key: 'a',
248258
}
259+
copyFileContentItem := &types.MenuItem{
260+
Label: self.c.Tr.CopyFileContent,
261+
OnPress: func() error {
262+
if err := self.copyFileContentToClipboard(node.GetPath()); err != nil {
263+
return err
264+
}
265+
self.c.Toast(self.c.Tr.FileContentCopiedToast)
266+
return nil
267+
},
268+
DisabledReason: self.require(self.singleItemSelected(
269+
func(node *filetree.CommitFileNode) *types.DisabledReason {
270+
if !node.IsFile() {
271+
return &types.DisabledReason{
272+
Text: self.c.Tr.ErrCannotCopyContentOfDirectory,
273+
ShowErrorInPanel: true,
274+
}
275+
}
276+
return nil
277+
}))(),
278+
Key: 'c',
279+
}
249280

250281
return self.c.Menu(types.CreateMenuOptions{
251282
Title: self.c.Tr.CopyToClipboardMenu,
@@ -254,6 +285,7 @@ func (self *CommitFilesController) openCopyMenu() error {
254285
copyPathItem,
255286
copyFileDiffItem,
256287
copyAllDiff,
288+
copyFileContentItem,
257289
},
258290
})
259291
}

pkg/i18n/english.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,13 @@ type TranslationSet struct {
8080
CopyFileDiffTooltip string
8181
CopySelectedDiff string
8282
CopyAllFilesDiff string
83+
CopyFileContent string
8384
NoContentToCopyError string
8485
FileNameCopiedToast string
8586
FilePathCopiedToast string
8687
FileDiffCopiedToast string
8788
AllFilesDiffCopiedToast string
89+
FileContentCopiedToast string
8890
FilterStagedFiles string
8991
FilterUnstagedFiles string
9092
FilterTrackedFiles string
@@ -696,6 +698,7 @@ type TranslationSet struct {
696698
PatchCopiedToClipboard string
697699
CopiedToClipboard string
698700
ErrCannotEditDirectory string
701+
ErrCannotCopyContentOfDirectory string
699702
ErrStageDirWithInlineMergeConflicts string
700703
ErrRepositoryMovedOrDeleted string
701704
ErrWorktreeMovedOrRemoved string
@@ -1120,11 +1123,13 @@ func EnglishTranslationSet() *TranslationSet {
11201123
CopyFileDiffTooltip: "If there are staged items, this command considers only them. Otherwise, it considers all the unstaged ones.",
11211124
CopySelectedDiff: "Diff of selected file",
11221125
CopyAllFilesDiff: "Diff of all files",
1126+
CopyFileContent: "Content of selected file",
11231127
NoContentToCopyError: "Nothing to copy",
11241128
FileNameCopiedToast: "File name copied to clipboard",
11251129
FilePathCopiedToast: "File path copied to clipboard",
11261130
FileDiffCopiedToast: "File diff copied to clipboard",
11271131
AllFilesDiffCopiedToast: "All files diff copied to clipboard",
1132+
FileContentCopiedToast: "File content copied to clipboard",
11281133
FilterStagedFiles: "Show only staged files",
11291134
FilterUnstagedFiles: "Show only unstaged files",
11301135
FilterTrackedFiles: "Show only tracked files",
@@ -1737,6 +1742,7 @@ func EnglishTranslationSet() *TranslationSet {
17371742
PatchCopiedToClipboard: "Patch copied to clipboard",
17381743
CopiedToClipboard: "copied to clipboard",
17391744
ErrCannotEditDirectory: "Cannot edit directories: you can only edit individual files",
1745+
ErrCannotCopyContentOfDirectory: "Cannot copy content of directories: you can only copy content of individual files",
17401746
ErrStageDirWithInlineMergeConflicts: "Cannot stage/unstage directory containing files with inline merge conflicts. Please fix up the merge conflicts first",
17411747
ErrRepositoryMovedOrDeleted: "Cannot find repo. It might have been moved or deleted ¯\\_(ツ)_/¯",
17421748
CommandLog: "Command log",

pkg/integration/tests/diff/copy_to_clipboard.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,21 @@ var CopyToClipboard = NewIntegrationTest(NewIntegrationTestArgs{
2323
shell.CreateDir("dir")
2424
shell.CreateFileAndAdd("dir/file1", "1st line\n")
2525
shell.Commit("1")
26-
shell.CreateFileAndAdd("dir/file1", "1st line\n2nd line\n")
26+
shell.UpdateFileAndAdd("dir/file1", "1st line\n2nd line\n")
2727
shell.CreateFileAndAdd("dir/file2", "file2\n")
2828
shell.Commit("2")
29+
shell.UpdateFileAndAdd("dir/file1", "1st line\n2nd line\n3rd line\n")
30+
shell.Commit("3")
2931
},
3032
Run: func(t *TestDriver, keys config.KeybindingConfig) {
3133
t.Views().Commits().
3234
Focus().
3335
Lines(
34-
Contains("2").IsSelected(),
36+
Contains("3").IsSelected(),
37+
Contains("2"),
3538
Contains("1"),
3639
).
40+
SelectNextItem().
3741
PressEnter()
3842

3943
t.Views().CommitFiles().
@@ -91,11 +95,22 @@ var CopyToClipboard = NewIntegrationTest(NewIntegrationTestArgs{
9195
Contains("diff --git a/dir/file1 b/dir/file1").Contains("+2nd line").DoesNotContain("+1st line").
9296
Contains("diff --git a/dir/file2 b/dir/file2").Contains("+file2"))
9397
})
98+
}).
99+
Press(keys.Files.CopyFileInfoToClipboard).
100+
Tap(func() {
101+
t.ExpectPopup().Menu().
102+
Title(Equals("Copy to clipboard")).
103+
Select(Contains("Content of selected file")).
104+
Confirm().
105+
Tap(func() {
106+
t.ExpectToast(Equals("File content copied to clipboard"))
107+
expectClipboard(t, Equals("1st line\n2nd line\n"))
108+
})
94109
})
95110

96111
t.Views().Commits().
97112
Focus().
98-
// Select both commits
113+
// Select commits 1 and 2
99114
Press(keys.Universal.RangeSelectDown).
100115
PressEnter()
101116

@@ -118,6 +133,17 @@ var CopyToClipboard = NewIntegrationTest(NewIntegrationTestArgs{
118133
expectClipboard(t,
119134
Contains("diff --git a/dir/file1 b/dir/file1").Contains("+1st line").Contains("+2nd line"))
120135
})
136+
}).
137+
Press(keys.Files.CopyFileInfoToClipboard).
138+
Tap(func() {
139+
t.ExpectPopup().Menu().
140+
Title(Equals("Copy to clipboard")).
141+
Select(Contains("Content of selected file")).
142+
Confirm().
143+
Tap(func() {
144+
t.ExpectToast(Equals("File content copied to clipboard"))
145+
expectClipboard(t, Equals("1st line\n2nd line\n"))
146+
})
121147
})
122148
},
123149
})

0 commit comments

Comments
 (0)