// package components // // import ( // "fmt" // "log/slog" // "tasksquire/common" // "time" // // "tasksquire/components/input" // "tasksquire/components/picker" // "tasksquire/components/timestampeditor" // "tasksquire/taskwarrior" // // "github.com/charmbracelet/bubbles/key" // "github.com/charmbracelet/bubbles/list" // "github.com/charmbracelet/bubbles/textarea" // "github.com/charmbracelet/bubbles/viewport" // tea "github.com/charmbracelet/bubbletea" // "github.com/charmbracelet/huh" // "github.com/charmbracelet/lipgloss" // ) // // type mode int // // const ( // modeNormal mode = iota // modeInsert // ) // // type TaskEditorPage struct { // common *common.Common // task taskwarrior.Task // // colWidth int // colHeight int // // mode mode // // columnCursor int // // area int // areaPicker *areaPicker // areas []area // // infoViewport viewport.Model // } // // func NewTaskEditorPage(com *common.Common, task taskwarrior.Task) *TaskEditorPage { // p := TaskEditorPage{ // common: com, // task: task, // } // // if p.task.Project == "" { // p.task.Project = "(none)" // } // // tagOptions := p.common.TW.GetTags() // // p.areas = []area{ // NewTaskEdit(p.common, &p.task, p.task.Uuid == ""), // NewTagEdit(p.common, &p.task.Tags, tagOptions), // NewTimeEdit(p.common, &p.task.Due, &p.task.Scheduled, &p.task.Wait, &p.task.Until), // NewDetailsEdit(p.common, &p.task), // } // // // p.areaList = NewAreaList(common, areaItems) // // p.selectedArea = areaTask // // p.columns = append([]tea.Model{p.areaList}, p.areas[p.selectedArea]...) // // p.areaPicker = NewAreaPicker(com, []string{"Task", "Tags", "Dates"}) // // p.infoViewport = viewport.New(0, 0) // if p.task.Uuid != "" { // p.infoViewport.SetContent(p.common.TW.GetInformation(&p.task)) // } // // p.columnCursor = 1 // if p.task.Uuid == "" { // p.mode = modeInsert // } else { // p.mode = modeNormal // } // // p.SetSize(com.Width(), com.Height()) // // return &p // } // // func (p *TaskEditorPage) SetSize(width, height int) { // p.common.SetSize(width, height) // // if width >= 70 { // p.colWidth = 70 - p.common.Styles.ColumnFocused.GetVerticalFrameSize() // } else { // p.colWidth = width - p.common.Styles.ColumnFocused.GetVerticalFrameSize() // } // // if height >= 40 { // p.colHeight = 40 - p.common.Styles.ColumnFocused.GetVerticalFrameSize() // } else { // p.colHeight = height - p.common.Styles.ColumnFocused.GetVerticalFrameSize() // } // // p.infoViewport.Width = width - p.colWidth - p.common.Styles.ColumnFocused.GetHorizontalFrameSize()*2 - 5 // if p.infoViewport.Width < 0 { // p.infoViewport.Width = 0 // } // p.infoViewport.Height = p.colHeight // } // // func (p *TaskEditorPage) Init() tea.Cmd { // var cmds []tea.Cmd // for _, a := range p.areas { // cmds = append(cmds, a.Init()) // } // return tea.Batch(cmds...) // } // // func (p *TaskEditorPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // switch msg := msg.(type) { // case tea.WindowSizeMsg: // p.SetSize(msg.Width, msg.Height) // case changeAreaMsg: // p.area = int(msg) // case changeModeMsg: // p.mode = mode(msg) // case prevColumnMsg: // p.columnCursor-- // maxCols := 2 // if p.task.Uuid != "" { // maxCols = 3 // } // if p.columnCursor < 0 { // p.columnCursor = maxCols - 1 // } // case nextColumnMsg: // p.columnCursor++ // maxCols := 2 // if p.task.Uuid != "" { // maxCols = 3 // } // if p.columnCursor >= maxCols { // p.columnCursor = 0 // } // case prevAreaMsg: // p.area-- // if p.area < 0 { // p.area = len(p.areas) - 1 // } // p.areas[p.area].SetCursor(-1) // case nextAreaMsg: // p.area++ // if p.area > len(p.areas)-1 { // p.area = 0 // } // p.areas[p.area].SetCursor(0) // } // // switch p.mode { // case modeNormal: // switch msg := msg.(type) { // case tea.KeyMsg: // switch { // case key.Matches(msg, p.common.Keymap.Back): // model, err := p.common.PopPage() // if err != nil { // slog.Error("page stack empty") // return nil, tea.Quit // } // return model, BackCmd // case key.Matches(msg, p.common.Keymap.Insert): // return p, changeMode(modeInsert) // case key.Matches(msg, p.common.Keymap.Ok): // model, err := p.common.PopPage() // if err != nil { // slog.Error("page stack empty") // return nil, tea.Quit // } // return model, p.updateTasksCmd // case key.Matches(msg, p.common.Keymap.PrevPage): // return p, prevArea() // case key.Matches(msg, p.common.Keymap.NextPage): // return p, nextArea() // case key.Matches(msg, p.common.Keymap.Left): // return p, prevColumn() // case key.Matches(msg, p.common.Keymap.Right): // return p, nextColumn() // case key.Matches(msg, p.common.Keymap.Up): // if p.columnCursor == 0 { // picker, cmd := p.areaPicker.Update(msg) // p.areaPicker = picker.(*areaPicker) // return p, cmd // } else if p.columnCursor == 1 { // model, cmd := p.areas[p.area].Update(prevFieldMsg{}) // p.areas[p.area] = model.(area) // return p, cmd // } else if p.columnCursor == 2 { // p.infoViewport.LineUp(1) // return p, nil // } // case key.Matches(msg, p.common.Keymap.Down): // if p.columnCursor == 0 { // picker, cmd := p.areaPicker.Update(msg) // p.areaPicker = picker.(*areaPicker) // return p, cmd // } else if p.columnCursor == 1 { // model, cmd := p.areas[p.area].Update(nextFieldMsg{}) // p.areas[p.area] = model.(area) // return p, cmd // } else if p.columnCursor == 2 { // p.infoViewport.LineDown(1) // return p, nil // } // } // } // // // var cmd tea.Cmd // // if p.columnCursor == 0 { // // p., cmd = p.areaList.Update(msg) // // p.selectedArea = p.areaList.(areaList).Area() // // cmds = append(cmds, cmd) // // } else { // // p.areas[p.selectedArea][p.columnCursor-1], cmd = p.areas[p.selectedArea][p.columnCursor-1].Update(msg) // // cmds = append(cmds, cmd) // // } // case modeInsert: // switch msg := msg.(type) { // case tea.KeyMsg: // switch { // case key.Matches(msg, p.common.Keymap.Back): // model, cmd := p.areas[p.area].Update(msg) // p.areas[p.area] = model.(area) // if cmd != nil { // _, ok := cmd().(input.SuppressBackMsg) // if ok { // return p, nil // } // } // return p, changeMode(modeNormal) // case key.Matches(msg, p.common.Keymap.Prev): // if p.columnCursor == 0 { // picker, cmd := p.areaPicker.Update(msg) // p.areaPicker = picker.(*areaPicker) // return p, cmd // } else if p.columnCursor == 1 { // model, cmd := p.areas[p.area].Update(prevFieldMsg{}) // p.areas[p.area] = model.(area) // return p, cmd // } // return p, nil // case key.Matches(msg, p.common.Keymap.Next): // if p.columnCursor == 0 { // picker, cmd := p.areaPicker.Update(msg) // p.areaPicker = picker.(*areaPicker) // return p, cmd // } else if p.columnCursor == 1 { // model, cmd := p.areas[p.area].Update(nextFieldMsg{}) // p.areas[p.area] = model.(area) // return p, cmd // } // return p, nil // case key.Matches(msg, p.common.Keymap.Ok): // isFiltering := p.areas[p.area].IsFiltering() // model, cmd := p.areas[p.area].Update(msg) // if p.area != 3 { // p.areas[p.area] = model.(area) // if isFiltering { // return p, cmd // } // return p, tea.Batch(cmd, nextField()) // } // return p, cmd // } // } // // if p.columnCursor == 0 { // picker, cmd := p.areaPicker.Update(msg) // p.areaPicker = picker.(*areaPicker) // return p, cmd // } else if p.columnCursor == 2 { // var cmd tea.Cmd // p.infoViewport, cmd = p.infoViewport.Update(msg) // return p, cmd // } else { // model, cmd := p.areas[p.area].Update(msg) // p.areas[p.area] = model.(area) // return p, cmd // } // } // return p, nil // } // // func (p *TaskEditorPage) View() string { // var focusedStyle, blurredStyle lipgloss.Style // if p.mode == modeInsert { // focusedStyle = p.common.Styles.ColumnInsert // } else { // focusedStyle = p.common.Styles.ColumnFocused // } // blurredStyle = p.common.Styles.ColumnBlurred // // var area string // if p.columnCursor == 1 { // area = focusedStyle.Copy().Width(p.colWidth).Height(p.colHeight).Render(p.areas[p.area].View()) // } else { // area = blurredStyle.Copy().Width(p.colWidth).Height(p.colHeight).Render(p.areas[p.area].View()) // } // // if p.task.Uuid != "" { // var infoView string // if p.columnCursor == 2 { // infoView = focusedStyle.Copy().Width(p.infoViewport.Width).Height(p.infoViewport.Height).Render(p.infoViewport.View()) // } else { // infoView = blurredStyle.Copy().Width(p.infoViewport.Width).Height(p.infoViewport.Height).Render(p.infoViewport.View()) // } // area = lipgloss.JoinHorizontal( // lipgloss.Top, // area, // infoView, // ) // } // // tabs := "" // for i, a := range p.areas { // style := p.common.Styles.Base // if i == p.area { // style = style.Bold(true).Foreground(p.common.Styles.Palette.Accent.GetForeground()) // } else { // style = style.Foreground(p.common.Styles.Palette.Muted.GetForeground()) // } // tabs += style.Render(fmt.Sprintf(" %s ", a.GetName())) // } // // page := lipgloss.JoinVertical( // lipgloss.Left, // tabs, // area, // ) // // // return lipgloss.Place(p.common.Width(), p.common.Height(), lipgloss.Center, lipgloss.Center, lipgloss.JoinHorizontal( // // lipgloss.Center, // // picker, // // area, // // )) // return lipgloss.Place(p.common.Width(), p.common.Height(), lipgloss.Center, lipgloss.Center, page) // } // // type area interface { // tea.Model // SetCursor(c int) // GetName() string // IsFiltering() bool // } // // type focusMsg struct{} // // type areaPicker struct { // common *common.Common // list list.Model // } // // type item string // // func (i item) Title() string { return string(i) } // func (i item) Description() string { return "test" } // func (i item) FilterValue() string { return "" } // // func NewAreaPicker(common *common.Common, items []string) *areaPicker { // listItems := make([]list.Item, len(items)) // for i, itm := range items { // listItems[i] = item(itm) // } // // list := list.New(listItems, list.DefaultDelegate{}, 20, 50) // list.SetFilteringEnabled(false) // list.SetShowStatusBar(false) // list.SetShowHelp(false) // list.SetShowPagination(false) // list.SetShowTitle(false) // // return &areaPicker{ // common: common, // list: list, // } // } // // func (a *areaPicker) Area() int { // // switch a.list.SelectedItem() { // // case item("Task"): // // return areaTask // // case item("Tags"): // // return areaTags // // case item("Dates"): // // return areaTime // // default: // // return areaTask // // } // return 0 // } // // func (a *areaPicker) Init() tea.Cmd { // return nil // } // // func (a *areaPicker) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // var cmds []tea.Cmd // var cmd tea.Cmd // cursor := a.list.Cursor() // // switch msg.(type) { // // case nextFieldMsg: // // a.list, cmd = a.list.Update(a.list.KeyMap.CursorDown) // // case prevFieldMsg: // // a.list, cmd = a.list.Update(a.list.KeyMap.CursorUp) // // } // a.list, cmd = a.list.Update(msg) // cmds = append(cmds, cmd) // if cursor != a.list.Cursor() { // cmds = append(cmds, changeArea(a.Area())) // } // // return a, tea.Batch(cmds...) // } // // func (a *areaPicker) View() string { // return a.list.View() // } // // type EditableField interface { // tea.Model // Focus() tea.Cmd // Blur() tea.Cmd // } // // type taskEdit struct { // common *common.Common // fields []EditableField // cursor int // // projectPicker *picker.Picker // // newProjectName *string // newAnnotation *string // udaValues map[string]*string // } // // func NewTaskEdit(com *common.Common, task *taskwarrior.Task, isNew bool) *taskEdit { // // newProject := "" // if task.Project == "" { // task.Project = "(none)" // } // // itemProvider := func() []list.Item { // projects := com.TW.GetProjects() // items := []list.Item{picker.NewItem("(none)")} // for _, proj := range projects { // items = append(items, picker.NewItem(proj)) // } // return items // } // onSelect := func(item list.Item) tea.Cmd { // return nil // } // onCreate := func(newProject string) tea.Cmd { // // The new project name will be used as the project value // // when the task is saved // return nil // } // // opts := []picker.PickerOption{picker.WithOnCreate(onCreate)} // // // Check if task has a pre-filled project (e.g., from ProjectTaskPickerPage) // hasPrefilledProject := task.Project != "" && task.Project != "(none)" // // if isNew && !hasPrefilledProject { // // New task with no project → start in filter mode for quick project search // opts = append(opts, picker.WithFilterByDefault(true)) // } else { // // Either existing task OR new task with pre-filled project → show list with project selected // opts = append(opts, picker.WithDefaultValue(task.Project)) // } // // projPicker := picker.New(com, "Project", itemProvider, onSelect, opts...) // projPicker.SetSize(70, 8) // projPicker.Blur() // // defaultKeymap := huh.NewDefaultKeyMap() // // fields := []EditableField{ // huh.NewInput(). // Title("Task"). // Value(&task.Description). // Validate(func(desc string) error { // if desc == "" { // return fmt.Errorf("task description is required") // } // return nil // }). // Inline(true). // Prompt(": "). // WithTheme(com.Styles.Form), // // projPicker, // // // huh.NewInput(). // // Title("New Project"). // // Value(&newProject). // // Inline(true). // // Prompt(": "). // // WithTheme(com.Styles.Form), // } // // udaValues := make(map[string]*string) // for _, uda := range com.Udas { // if uda.Name == "parenttask" { // continue // } // switch uda.Type { // case taskwarrior.UdaTypeNumeric: // val := "" // udaValues[uda.Name] = &val // fields = append(fields, huh.NewInput(). // Title(uda.Label). // Value(udaValues[uda.Name]). // Validate(taskwarrior.ValidateNumeric). // Inline(true). // Prompt(": "). // WithTheme(com.Styles.Form)) // case taskwarrior.UdaTypeString: // if len(uda.Values) > 0 { // var val string // values := make([]string, len(uda.Values)) // for i, v := range uda.Values { // values[i] = v // if v == "" { // values[i] = "(none)" // } // if v == uda.Default { // val = values[i] // } // } // if val == "" { // val = values[0] // } // if v, ok := task.Udas[uda.Name]; ok { // //TODO: handle uda types correctly // val = v.(string) // } // udaValues[uda.Name] = &val // // fields = append(fields, huh.NewSelect[string](). // Options(huh.NewOptions(values...)...). // Title(uda.Label). // Value(udaValues[uda.Name]). // WithKeyMap(defaultKeymap). // WithTheme(com.Styles.Form)) // } else { // val := "" // udaValues[uda.Name] = &val // fields = append(fields, huh.NewInput(). // Title(uda.Label). // Value(udaValues[uda.Name]). // Inline(true). // Prompt(": "). // WithTheme(com.Styles.Form)) // } // case taskwarrior.UdaTypeDate: // val := "" // udaValues[uda.Name] = &val // fields = append(fields, huh.NewInput(). // Title(uda.Label). // Value(udaValues[uda.Name]). // Validate(taskwarrior.ValidateDate). // Inline(true). // Prompt(": "). // WithTheme(com.Styles.Form)) // case taskwarrior.UdaTypeDuration: // val := "" // udaValues[uda.Name] = &val // fields = append(fields, huh.NewInput(). // Title(uda.Label). // Value(udaValues[uda.Name]). // Validate(taskwarrior.ValidateDuration). // Inline(true). // Prompt(": "). // WithTheme(com.Styles.Form)) // } // } // // newAnnotation := "" // fields = append(fields, huh.NewInput(). // Title("New Annotation"). // Value(&newAnnotation). // Inline(true). // Prompt(": "). // WithTheme(com.Styles.Form)) // // t := taskEdit{ // common: com, // fields: fields, // projectPicker: projPicker, // // udaValues: udaValues, // // // newProjectName: &newProject, // newAnnotation: &newAnnotation, // } // // t.fields[0].Focus() // // return &t // } // // func (t *taskEdit) GetName() string { // return "Task" // } // // func (t *taskEdit) IsFiltering() bool { // if f, ok := t.fields[t.cursor].(interface{ IsFiltering() bool }); ok { // return f.IsFiltering() // } // return false // } // // func (t *taskEdit) SetCursor(c int) { // t.fields[t.cursor].Blur() // if c < 0 { // t.cursor = len(t.fields) - 1 // } else { // t.cursor = c // } // t.fields[t.cursor].Focus() // } // // func (t *taskEdit) Init() tea.Cmd { // var cmds []tea.Cmd // // Ensure focus on the active field (especially for the first one) // if len(t.fields) > 0 { // cmds = append(cmds, func() tea.Msg { // return focusMsg{} // }) // } // for _, f := range t.fields { // cmds = append(cmds, f.Init()) // } // return tea.Batch(cmds...) // } // // func (t *taskEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // switch msg.(type) { // case focusMsg: // if len(t.fields) > 0 { // return t, t.fields[t.cursor].Focus() // } // case nextFieldMsg: // if t.cursor == len(t.fields)-1 { // t.fields[t.cursor].Blur() // return t, nextArea() // } // t.fields[t.cursor].Blur() // t.cursor++ // t.fields[t.cursor].Focus() // case prevFieldMsg: // if t.cursor == 0 { // t.fields[t.cursor].Blur() // return t, prevArea() // } // t.fields[t.cursor].Blur() // t.cursor-- // t.fields[t.cursor].Focus() // default: // field, cmd := t.fields[t.cursor].Update(msg) // t.fields[t.cursor] = field.(EditableField) // return t, cmd // } // // return t, nil // } // // func (t *taskEdit) View() string { // views := make([]string, len(t.fields)) // for i, field := range t.fields { // views[i] = field.View() // if i < len(t.fields)-1 { // views[i] += "\n" // } // } // return lipgloss.JoinVertical( // lipgloss.Left, // views..., // ) // } // // type tagEdit struct { // common *common.Common // fields []huh.Field // // cursor int // } // // func NewTagEdit(common *common.Common, selected *[]string, options []string) *tagEdit { // defaultKeymap := huh.NewDefaultKeyMap() // // t := tagEdit{ // common: common, // fields: []huh.Field{ // input.NewMultiSelect(common). // Options(true, input.NewOptions(options...)...). // // Key("tags"). // Title("Tags"). // Value(selected). // Filterable(true). // WithKeyMap(defaultKeymap). // WithTheme(common.Styles.Form), // }, // } // // return &t // } // // func (t *tagEdit) GetName() string { // return "Tags" // } // // func (t *tagEdit) IsFiltering() bool { // if f, ok := t.fields[t.cursor].(interface{ IsFiltering() bool }); ok { // return f.IsFiltering() // } // return false // } // // func (t *tagEdit) SetCursor(c int) { // t.fields[t.cursor].Blur() // if c < 0 { // t.cursor = len(t.fields) - 1 // } else { // t.cursor = c // } // t.fields[t.cursor].Focus() // } // // func (t *tagEdit) Init() tea.Cmd { // return nil // } // // func (t *tagEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // switch msg.(type) { // case nextFieldMsg: // if t.cursor == len(t.fields)-1 { // t.fields[t.cursor].Blur() // return t, nextArea() // } // t.fields[t.cursor].Blur() // t.cursor++ // t.fields[t.cursor].Focus() // case prevFieldMsg: // if t.cursor == 0 { // t.fields[t.cursor].Blur() // return t, prevArea() // } // t.fields[t.cursor].Blur() // t.cursor-- // t.fields[t.cursor].Focus() // default: // field, cmd := t.fields[t.cursor].Update(msg) // t.fields[t.cursor] = field.(huh.Field) // return t, cmd // } // return t, nil // } // // func (t tagEdit) View() string { // views := make([]string, len(t.fields)) // for i, field := range t.fields { // views[i] = field.View() // } // return lipgloss.JoinVertical( // lipgloss.Left, // views..., // ) // } // // type timeEdit struct { // common *common.Common // fields []*timestampeditor.TimestampEditor // // cursor int // // // Store task field pointers to update them // due *string // scheduled *string // wait *string // until *string // } // // func NewTimeEdit(common *common.Common, due *string, scheduled *string, wait *string, until *string) *timeEdit { // // Create timestamp editors for each date field // dueEditor := timestampeditor.New(common). // Title("Due"). // Description("When the task is due"). // ValueFromString(*due) // // scheduledEditor := timestampeditor.New(common). // Title("Scheduled"). // Description("When to start working on the task"). // ValueFromString(*scheduled) // // waitEditor := timestampeditor.New(common). // Title("Wait"). // Description("Hide task until this date"). // ValueFromString(*wait) // // untilEditor := timestampeditor.New(common). // Title("Until"). // Description("Task expires after this date"). // ValueFromString(*until) // // t := timeEdit{ // common: common, // fields: []*timestampeditor.TimestampEditor{ // dueEditor, // scheduledEditor, // waitEditor, // untilEditor, // }, // due: due, // scheduled: scheduled, // wait: wait, // until: until, // } // // // Focus the first field // if len(t.fields) > 0 { // t.fields[0].Focus() // } // // return &t // } // // func (t *timeEdit) GetName() string { // return "Dates" // } // // func (t *timeEdit) IsFiltering() bool { // return false // } // // func (t *timeEdit) SetCursor(c int) { // if len(t.fields) == 0 { // return // } // // // Blur the current field // t.fields[t.cursor].Blur() // // // Set new cursor position // if c < 0 { // t.cursor = len(t.fields) - 1 // } else { // t.cursor = c // } // // // Focus the new field // t.fields[t.cursor].Focus() // } // // func (t *timeEdit) Init() tea.Cmd { // return nil // } // // func (t *timeEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // switch msg := msg.(type) { // case nextFieldMsg: // if t.cursor == len(t.fields)-1 { // // Update task field before moving to next area // t.syncToTaskFields() // t.fields[t.cursor].Blur() // return t, nextArea() // } // t.fields[t.cursor].Blur() // t.cursor++ // t.fields[t.cursor].Focus() // return t, nil // case prevFieldMsg: // if t.cursor == 0 { // // Update task field before moving to previous area // t.syncToTaskFields() // t.fields[t.cursor].Blur() // return t, prevArea() // } // t.fields[t.cursor].Blur() // t.cursor-- // t.fields[t.cursor].Focus() // return t, nil // default: // // Update the current timestamp editor // model, cmd := t.fields[t.cursor].Update(msg) // t.fields[t.cursor] = model.(*timestampeditor.TimestampEditor) // return t, cmd // } // } // // func (t *timeEdit) View() string { // views := make([]string, len(t.fields)) // // for i, field := range t.fields { // views[i] = field.View() // if i < len(t.fields)-1 { // views[i] += "\n" // } // } // // return lipgloss.JoinVertical( // lipgloss.Left, // views..., // ) // } // // // syncToTaskFields converts the timestamp editor values back to task field strings // func (t *timeEdit) syncToTaskFields() { // // Update the task fields with values from the timestamp editors // // GetValueString() returns empty string for unset timestamps // if len(t.fields) > 0 { // *t.due = t.fields[0].GetValueString() // } // if len(t.fields) > 1 { // *t.scheduled = t.fields[1].GetValueString() // } // if len(t.fields) > 2 { // *t.wait = t.fields[2].GetValueString() // } // if len(t.fields) > 3 { // *t.until = t.fields[3].GetValueString() // } // } // // type detailsEdit struct { // com *common.Common // vp viewport.Model // ta textarea.Model // details string // // renderer *glamour.TermRenderer // } // // func NewDetailsEdit(com *common.Common, task *taskwarrior.Task) *detailsEdit { // // renderer, err := glamour.NewTermRenderer( // // // glamour.WithStandardStyle("light"), // // glamour.WithAutoStyle(), // // glamour.WithWordWrap(40), // // ) // // if err != nil { // // slog.Error(err.Error()) // // return nil // // } // // vp := viewport.New(com.Width(), 40-com.Styles.ColumnFocused.GetVerticalFrameSize()) // ta := textarea.New() // ta.SetWidth(70) // ta.SetHeight(40 - com.Styles.ColumnFocused.GetVerticalFrameSize() - 2) // ta.ShowLineNumbers = false // ta.FocusedStyle.CursorLine = lipgloss.NewStyle() // ta.Focus() // if task.Udas["details"] != nil { // ta.SetValue(task.Udas["details"].(string)) // } // d := detailsEdit{ // com: com, // // renderer: renderer, // vp: vp, // ta: ta, // } // // return &d // } // // func (d *detailsEdit) GetName() string { // return "Details" // } // // func (d *detailsEdit) IsFiltering() bool { // return false // } // // func (d *detailsEdit) SetCursor(c int) { // } // // func (d *detailsEdit) Init() tea.Cmd { // return textarea.Blink // } // // func (d *detailsEdit) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // switch msg.(type) { // case nextFieldMsg: // return d, nextArea() // case prevFieldMsg: // return d, prevArea() // default: // var vpCmd, taCmd tea.Cmd // d.vp, vpCmd = d.vp.Update(msg) // d.ta, taCmd = d.ta.Update(msg) // return d, tea.Batch(vpCmd, taCmd) // } // } // // func (d *detailsEdit) View() string { // return d.ta.View() // } // // func (p *TaskEditorPage) updateTasksCmd() tea.Msg { // p.task.Project = p.areas[0].(*taskEdit).projectPicker.GetValue() // // if p.task.Project == "(none)" { // p.task.Project = "" // } // // for _, uda := range p.common.Udas { // if val, ok := p.areas[0].(*taskEdit).udaValues[uda.Name]; ok { // if *val == "(none)" { // *val = "" // } // p.task.Udas[uda.Name] = *val // } // } // // // Sync timestamp fields from the timeEdit area (area 2) // p.areas[2].(*timeEdit).syncToTaskFields() // // if *(p.areas[0].(*taskEdit).newAnnotation) != "" { // p.task.Annotations = append(p.task.Annotations, taskwarrior.Annotation{ // Entry: time.Now().Format("20060102T150405Z"), // Description: *(p.areas[0].(*taskEdit).newAnnotation), // }) // } // // if _, ok := p.task.Udas["details"]; ok || p.areas[3].(*detailsEdit).ta.Value() != "" { // p.task.Udas["details"] = p.areas[3].(*detailsEdit).ta.Value() // } // // p.common.TW.ImportTask(&p.task) // return UpdatedTasksMsg{} // } // // // type StatusLine struct { ... } // // ...