Allow opening the editor while creating a ticket with Ctrl+e.
Draft headline from the create input is passed into $EDITOR so title and description can be written before the ticket is saved. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+44
-3
@@ -21,9 +21,10 @@ import (
|
|||||||
|
|
||||||
// editorFinishedMsg is sent after the external $EDITOR exits.
|
// editorFinishedMsg is sent after the external $EDITOR exits.
|
||||||
type editorFinishedMsg struct {
|
type editorFinishedMsg struct {
|
||||||
ticketID string
|
ticketID string // empty when create==true
|
||||||
path string
|
path string
|
||||||
err error
|
err error
|
||||||
|
create bool // true: create ticket from edited file
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mode is the active UI mode.
|
// Mode is the active UI mode.
|
||||||
@@ -374,6 +375,20 @@ func (m Model) updateInput(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
|||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
|
|
||||||
|
case key.Matches(msg, m.keys.EditInEditor):
|
||||||
|
if m.mode != ModeCreate || m.creatingProject {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
m.clearStatus()
|
||||||
|
cmd, err := m.openEditorForNewTicket()
|
||||||
|
if err != nil {
|
||||||
|
m.setError(err)
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
m.input.Blur()
|
||||||
|
m.mode = ModeList
|
||||||
|
return m, cmd
|
||||||
|
|
||||||
case key.Matches(msg, m.keys.Enter):
|
case key.Matches(msg, m.keys.Enter):
|
||||||
value := strings.TrimSpace(m.input.Value())
|
value := strings.TrimSpace(m.input.Value())
|
||||||
if m.mode == ModeCreate {
|
if m.mode == ModeCreate {
|
||||||
@@ -397,7 +412,7 @@ func (m Model) updateInput(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
|||||||
m.setStatus(fmt.Sprintf("created project %s", id))
|
m.setStatus(fmt.Sprintf("created project %s", id))
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
if err := m.createTicket(value); err != nil {
|
if err := m.createTicket(value, ""); err != nil {
|
||||||
m.setError(err)
|
m.setError(err)
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
@@ -474,6 +489,21 @@ func (m Model) openEditorForSelected() (tea.Cmd, error) {
|
|||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m Model) openEditorForNewTicket() (tea.Cmd, error) {
|
||||||
|
title := strings.TrimSpace(m.input.Value())
|
||||||
|
if title == "" {
|
||||||
|
title = "New ticket"
|
||||||
|
}
|
||||||
|
path, err := ticket.WriteEditFile(ticket.Ticket{Title: title})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c := ticket.EditorCmd(path)
|
||||||
|
return tea.ExecProcess(c, func(err error) tea.Msg {
|
||||||
|
return editorFinishedMsg{path: path, err: err, create: true}
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m Model) handleEditorFinished(msg editorFinishedMsg) (tea.Model, tea.Cmd) {
|
func (m Model) handleEditorFinished(msg editorFinishedMsg) (tea.Model, tea.Cmd) {
|
||||||
defer func() { _ = os.Remove(msg.path) }()
|
defer func() { _ = os.Remove(msg.path) }()
|
||||||
|
|
||||||
@@ -493,6 +523,16 @@ func (m Model) handleEditorFinished(msg editorFinishedMsg) (tea.Model, tea.Cmd)
|
|||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if msg.create {
|
||||||
|
if err := m.createTicket(title, description); err != nil {
|
||||||
|
m.setError(err)
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
m.mode = ModeList
|
||||||
|
m.setStatus("created")
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
before, err := m.store.Get(msg.ticketID)
|
before, err := m.store.Get(msg.ticketID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.setError(err)
|
m.setError(err)
|
||||||
@@ -521,11 +561,12 @@ func (m Model) handleEditorFinished(msg editorFinishedMsg) (tea.Model, tea.Cmd)
|
|||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) createTicket(title string) error {
|
func (m *Model) createTicket(title, description string) error {
|
||||||
cmd := &command.CreateTicket{
|
cmd := &command.CreateTicket{
|
||||||
Store: m.store,
|
Store: m.store,
|
||||||
Ticket: ticket.Ticket{
|
Ticket: ticket.Ticket{
|
||||||
Title: title,
|
Title: title,
|
||||||
|
Description: description,
|
||||||
ProjectID: m.cfg.ActiveProject,
|
ProjectID: m.cfg.ActiveProject,
|
||||||
Status: m.boardList.DefaultStatus(),
|
Status: m.boardList.DefaultStatus(),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,10 +14,14 @@ type helpEntry struct {
|
|||||||
func (m Model) helpEntries() []helpEntry {
|
func (m Model) helpEntries() []helpEntry {
|
||||||
switch m.mode {
|
switch m.mode {
|
||||||
case ModeCreate:
|
case ModeCreate:
|
||||||
return []helpEntry{
|
entries := []helpEntry{
|
||||||
{"enter", "save"},
|
{"enter", "save"},
|
||||||
{"esc", "cancel"},
|
{"esc", "cancel"},
|
||||||
}
|
}
|
||||||
|
if !m.creatingProject {
|
||||||
|
entries = append([]helpEntry{{"ctrl+e", "editor"}}, entries...)
|
||||||
|
}
|
||||||
|
return entries
|
||||||
case ModeSearch:
|
case ModeSearch:
|
||||||
return []helpEntry{
|
return []helpEntry{
|
||||||
{"enter", "apply"},
|
{"enter", "apply"},
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ type KeyMap struct {
|
|||||||
Board key.Binding
|
Board key.Binding
|
||||||
Status key.Binding
|
Status key.Binding
|
||||||
Edit key.Binding
|
Edit key.Binding
|
||||||
|
EditInEditor key.Binding // ctrl+e — open $EDITOR while creating
|
||||||
Delete key.Binding // x — confirm first
|
Delete key.Binding // x — confirm first
|
||||||
DeleteForce key.Binding // X — immediate
|
DeleteForce key.Binding // X — immediate
|
||||||
ConfirmYes key.Binding
|
ConfirmYes key.Binding
|
||||||
@@ -57,6 +58,10 @@ func DefaultKeyMap() KeyMap {
|
|||||||
key.WithKeys("e"),
|
key.WithKeys("e"),
|
||||||
key.WithHelp("e", "edit"),
|
key.WithHelp("e", "edit"),
|
||||||
),
|
),
|
||||||
|
EditInEditor: key.NewBinding(
|
||||||
|
key.WithKeys("ctrl+e"),
|
||||||
|
key.WithHelp("ctrl+e", "editor"),
|
||||||
|
),
|
||||||
Delete: key.NewBinding(
|
Delete: key.NewBinding(
|
||||||
key.WithKeys("x"),
|
key.WithKeys("x"),
|
||||||
key.WithHelp("x", "delete"),
|
key.WithHelp("x", "delete"),
|
||||||
|
|||||||
Reference in New Issue
Block a user