Repository: jesseduffield/lazygit (language: go)

Issue:
Feature request: Allow defining custom popup title when using `showOutput`
**Is your feature request related to a problem? Please describe.**

When using the `showOutput` option to display the output of non-trivial commands, the popup title is no longer descriptive in the sense that it's too verbose. Even if one would like to see the full command, this very quickly is no longer possible since it gets cut off. Here is an example:

<img width="847" alt="CleanShot 2024-05-19 at 11 06 29@2x" src="https://github.com/jesseduffield/lazygit/assets/42832087/5b15d2a4-f28a-4462-b083-82c788e2d7b0">


**Describe the solution you'd like**

I would like to define a custom title. Static strings would work for my use cases. For the above example I might want to have _"Jira Issue Details"_ as the title.

The schema could support both a "shorthand" boolean value and object configuration like this:

```yaml
command: 'jira issue view $(printf %s {{.SelectedLocalBranch.Name}} | grep -o "CUB-[0-9]*") --comments 5'
showOutput:
  title: Jira Issue Details
```

Being able to use templates would be the cherry on the top.

**Describe alternatives you've considered**

One could extract the command in a script that results in a command with a very short path. That added step is very undesirable for me personally and the result would only be mildly better.

**Additional context**

Thank you so much creating this wonderful tool and considering my humble request 🤗 

<!--
You may be able to add your desired feature with a custom command. Check out the examples here: https://github.com/jesseduffield/lazygit/wiki/Custom-Commands-Compendium

If a custom command does what you want but you still want to see the feature built-in to lazygit, feel free to paste the custom command into the issue to help us better understand the functionality you want.

We also encourage you to put up a PR yourself! Who cares if you've never written Go before, neither did any of the existing contributors before their first lazygit PR! Check out the PR tutorial here: https://www.youtube.com/watch?v=kNavnhzZHtk&ab_channel=JesseDuffield

Also check out the contributing guide here: https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md
-->



Discussion / hints:

Fix patch:
diff --git a/docs/Custom_Command_Keybindings.md b/docs/Custom_Command_Keybindings.md
index 426d6f8f699..1053f9e4579 100644
--- a/docs/Custom_Command_Keybindings.md
+++ b/docs/Custom_Command_Keybindings.md
@@ -59,6 +59,7 @@ For a given custom command, here are the allowed fields:
 | description | Label for the custom command when displayed in the keybindings menu | no |
 | stream | Whether you want to stream the command's output to the Command Log panel | no |
 | showOutput | Whether you want to show the command's output in a popup within Lazygit | no |
+| outputTitle | The title to display in the popup panel if showOutput is true. If left unset, the command will be used as the title. | no |
 | after | Actions to take after the command has completed | no |
 
 Here are the options for the `after` key:
diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go
index 2df6e60b88e..904b2014159 100644
--- a/pkg/config/user_config.go
+++ b/pkg/config/user_config.go
@@ -581,6 +581,8 @@ type CustomCommand struct {
 	Stream bool `yaml:"stream"`
 	// If true, show the command's output in a popup within Lazygit
 	ShowOutput bool `yaml:"showOutput"`
+	// The title to display in the popup panel if showOutput is true. If left unset, the command will be used as the title.
+	OutputTitle string `yaml:"outputTitle"`
 	// Actions to take after the command has completed
 	After CustomCommandAfterHook `yaml:"after"`
 }
diff --git a/pkg/gui/services/custom_commands/handler_creator.go b/pkg/gui/services/custom_commands/handler_creator.go
index 9a127f3623f..c1cfe09cbcd 100644
--- a/pkg/gui/services/custom_commands/handler_creator.go
+++ b/pkg/gui/services/custom_commands/handler_creator.go
@@ -292,7 +292,15 @@ func (self *HandlerCreator) finalHandler(customCommand config.CustomCommand, ses
 			if strings.TrimSpace(output) == "" {
 				output = self.c.Tr.EmptyOutput
 			}
-			return self.c.Alert(cmdStr, output)
+
+			title := cmdStr
+			if customCommand.OutputTitle != "" {
+				title, err = resolveTemplate(customCommand.OutputTitle)
+				if err != nil {
+					return err
+				}
+			}
+			return self.c.Alert(title, output)
 		}
 
 		return nil
diff --git a/schema/config.json b/schema/config.json
index 9764e2286c6..626ad157379 100644
--- a/schema/config.json
+++ b/schema/config.json
@@ -924,6 +924,10 @@
             "type": "boolean",
             "description": "If true, show the command's output in a popup within Lazygit"
           },
+          "outputTitle": {
+            "type": "string",
+            "description": "The title to display in the popup panel if showOutput is true. If left unset, the command will be used as the title."
+          },
           "after": {
             "properties": {
               "checkForConflicts": {


Test patch:
diff --git a/pkg/integration/tests/custom_commands/show_output_in_panel.go b/pkg/integration/tests/custom_commands/show_output_in_panel.go
new file mode 100644
index 00000000000..e98f372e673
--- /dev/null
+++ b/pkg/integration/tests/custom_commands/show_output_in_panel.go
@@ -0,0 +1,57 @@
+package custom_commands
+
+import (
+	"fmt"
+
+	"github.com/jesseduffield/lazygit/pkg/config"
+	. "github.com/jesseduffield/lazygit/pkg/integration/components"
+)
+
+var ShowOutputInPanel = NewIntegrationTest(NewIntegrationTestArgs{
+	Description:  "Run a command and show the output in a panel",
+	ExtraCmdArgs: []string{},
+	Skip:         false,
+	SetupRepo: func(shell *Shell) {
+		shell.EmptyCommit("my change")
+	},
+	SetupConfig: func(cfg *config.AppConfig) {
+		cfg.UserConfig.CustomCommands = []config.CustomCommand{
+			{
+				Key:        "X",
+				Context:    "commits",
+				Command:    "printf '%s' '{{ .SelectedLocalCommit.Name }}'",
+				ShowOutput: true,
+			},
+			{
+				Key:         "Y",
+				Context:     "commits",
+				Command:     "printf '%s' '{{ .SelectedLocalCommit.Name }}'",
+				ShowOutput:  true,
+				OutputTitle: "Subject of commit {{ .SelectedLocalCommit.Hash }}",
+			},
+		}
+	},
+	Run: func(t *TestDriver, keys config.KeybindingConfig) {
+		t.Views().Commits().
+			Focus().
+			Lines(
+				Contains("my change").IsSelected(),
+			).
+			Press("X")
+
+		t.ExpectPopup().Alert().
+			// Uses cmd string as title if no outputTitle is provided
+			Title(Equals("printf '%s' 'my change'")).
+			Content(Equals("my change")).
+			Confirm()
+
+		t.Views().Commits().
+			Press("Y")
+
+		hash := t.Git().GetCommitHash("HEAD")
+		t.ExpectPopup().Alert().
+			// Uses provided outputTitle with template fields resolved
+			Title(Equals(fmt.Sprintf("Subject of commit %s", hash))).
+			Content(Equals("my change"))
+	},
+})
diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go
index e043d4a8a21..c65db5abcdc 100644
--- a/pkg/integration/tests/test_list.go
+++ b/pkg/integration/tests/test_list.go
@@ -113,6 +113,7 @@ var tests = []*components.IntegrationTest{
 	custom_commands.MenuFromCommandsOutput,
 	custom_commands.MultiplePrompts,
 	custom_commands.OmitFromHistory,
+	custom_commands.ShowOutputInPanel,
 	custom_commands.SuggestionsCommand,
 	custom_commands.SuggestionsPreset,
 	demo.AmendOldCommit,