Skip to content

Commit

Permalink
feat: allow copying context to system clipboard
Browse files Browse the repository at this point in the history
  • Loading branch information
dhth committed Jul 17, 2024
1 parent c8c2be4 commit ae25b22
Show file tree
Hide file tree
Showing 10 changed files with 105 additions and 31 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ B open all bookmarks in the current task's context
c update context for a task
ctrl+d archive/unarchive task
ctrl+x delete task
y copy selected task's context to system clipboard
v toggle between compact and spacious view
Active Tasks List
Expand All @@ -214,6 +215,7 @@ K move task one position up
Task Details Pane
h/l move backwards/forwards when in the task details view
y copy selected task's context to system clipboard
B open all bookmarks in the current task's context
Context Bookmarks List
Expand Down
2 changes: 2 additions & 0 deletions cmd/guide.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ order). You can override this behavior by passing the "editor" flag to omm, like
Go ahead, press "c". Try changing the text, and then save the file. This context
text should get updated accordingly.
Once saved, you can also copy a tasks's context to your system clipboard by pressing "y".
`,
true,
},
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/dhth/omm
go 1.22.5

require (
github.com/atotto/clipboard v0.1.4
github.com/charmbracelet/bubbles v0.18.0
github.com/charmbracelet/bubbletea v0.26.6
github.com/charmbracelet/lipgloss v0.11.0
Expand All @@ -15,7 +16,6 @@ require (
)

require (
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/x/ansi v0.1.2 // indirect
github.com/charmbracelet/x/input v0.1.2 // indirect
Expand Down
8 changes: 8 additions & 0 deletions internal/ui/cmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"database/sql"

"github.com/atotto/clipboard"
tea "github.com/charmbracelet/bubbletea"
pers "github.com/dhth/omm/internal/persistence"
"github.com/dhth/omm/internal/types"
Expand Down Expand Up @@ -115,3 +116,10 @@ func openURLsDarwin(urls []string) tea.Cmd {
return urlsOpenedDarwinMsg{urls, err}
})
}

func copyContextToClipboard(context string) tea.Cmd {
return func() tea.Msg {
err := clipboard.WriteAll(context)
return contextWrittenToCBMsg{err}
}
}
2 changes: 2 additions & 0 deletions internal/ui/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ B open all bookmarks in the current task's context
c update context for a task
ctrl+d archive/unarchive task
ctrl+x delete task
y copy selected task's context to system clipboard
v toggle between compact and spacious view`),
helpSubHeadingStyle.Render("Active Tasks List"),
helpSectionStyle.Render(`q/esc/ctrl+c quit
Expand All @@ -68,6 +69,7 @@ J move task one position down
K move task one position up`),
helpSubHeadingStyle.Render("Task Details Pane"),
helpSectionStyle.Render(`h/l move backwards/forwards when in the task details view
y copy current task's context to system clipboard
B open all bookmarks in the current task's context`),
helpSubHeadingStyle.Render("Context Bookmarks List"),
helpSectionStyle.Render(`⏎ open URL in browser`),
Expand Down
3 changes: 2 additions & 1 deletion internal/ui/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,12 @@ type model struct {
helpVPReady bool
quitting bool
showHelpIndicator bool
successMsg string
errorMsg string
taskInput textinput.Model
activeView activeView
lastActiveView activeView
lastActiveList taskListType
activeTaskList taskListType
tlTitleStyle lipgloss.Style
atlTitleStyle lipgloss.Style
tlSelStyle lipgloss.Style
Expand Down
4 changes: 4 additions & 0 deletions internal/ui/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,7 @@ type urlsOpenedDarwinMsg struct {
urls []string
err error
}

type contextWrittenToCBMsg struct {
err error
}
14 changes: 10 additions & 4 deletions internal/ui/styles.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ const (
helpTitleColor = "#83a598"
helpHeaderColor = "#83a598"
helpSectionColor = "#bdae93"
statusBarColor = "#fb4934"
sBSuccessMsgColor = "#d3869b"
sBErrMsgColor = "#fb4934"
footerColor = "#928374"
)

Expand Down Expand Up @@ -58,9 +59,14 @@ var (
PaddingBottom(1).
PaddingLeft(2)

statusBarStyle = lipgloss.NewStyle().
PaddingLeft(2).
Foreground(lipgloss.Color(statusBarColor))
statusBarMsgStyle = lipgloss.NewStyle().
PaddingLeft(2)

sBErrMsgStyle = statusBarMsgStyle.
Foreground(lipgloss.Color(sBErrMsgColor))

sBSuccessMsgStyle = statusBarMsgStyle.
Foreground(lipgloss.Color(sBSuccessMsgColor))

taskDetailsStyle = lipgloss.NewStyle().
PaddingLeft(2).
Expand Down
83 changes: 62 additions & 21 deletions internal/ui/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const (
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
var cmds []tea.Cmd
m.successMsg = ""
m.errorMsg = ""

if m.activeView == taskEntryView {
Expand All @@ -33,14 +34,14 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch keypress := msg.String(); keypress {
case "esc", "ctrl+c":
m.activeView = taskListView
m.lastActiveList = activeTasks
m.activeTaskList = activeTasks
case "enter":
taskSummary := m.taskInput.Value()
taskSummary = strings.TrimSpace(taskSummary)

if taskSummary == "" {
m.activeView = taskListView
m.lastActiveList = activeTasks
m.activeTaskList = activeTasks
break
}

Expand All @@ -51,13 +52,13 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
cmds = append(cmds, cmd)
m.taskInput.Reset()
m.activeView = taskListView
m.lastActiveList = activeTasks
m.activeTaskList = activeTasks
case taskUpdateSummary:
cmd = updateTaskSummary(m.db, m.taskIndex, m.taskId, taskSummary)
cmds = append(cmds, cmd)
m.taskInput.Reset()
m.activeView = taskListView
m.lastActiveList = activeTasks
m.activeTaskList = activeTasks
}
}
}
Expand All @@ -71,7 +72,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case tea.WindowSizeMsg:
w, h := listStyle.GetFrameSize()
_, h2 := headerStyle.GetFrameSize()
_, h3 := statusBarStyle.GetFrameSize()
_, h3 := statusBarMsgStyle.GetFrameSize()
m.terminalWidth = msg.Width
m.terminalHeight = msg.Height
m.taskList.SetWidth(msg.Width - w)
Expand Down Expand Up @@ -143,7 +144,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

if m.activeView == archivedTaskListView {
m.activeView = taskListView
m.lastActiveList = activeTasks
m.activeTaskList = activeTasks
m.lastActiveView = av
break
}
Expand All @@ -152,9 +153,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.activeView = m.lastActiveView
switch m.activeView {
case taskListView:
m.lastActiveList = activeTasks
m.activeTaskList = activeTasks
case archivedTaskListView:
m.lastActiveList = archivedTasks
m.activeTaskList = archivedTasks
}
break
}
Expand Down Expand Up @@ -182,10 +183,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch m.activeView {
case taskListView:
m.activeView = archivedTaskListView
m.lastActiveList = archivedTasks
m.activeTaskList = archivedTasks
case archivedTaskListView:
m.activeView = taskListView
m.lastActiveList = activeTasks
m.activeTaskList = activeTasks
}

case "2", "3", "4", "5", "6", "7", "8", "9":
Expand Down Expand Up @@ -510,7 +511,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var ok bool
var index int

switch m.lastActiveList {
switch m.activeTaskList {
case activeTasks:
t, ok = m.taskList.SelectedItem().(types.Task)
if !ok {
Expand Down Expand Up @@ -557,7 +558,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var taskList list.Model
var archivedTaskList list.Model
_, h2 := headerStyle.GetFrameSize()
_, h3 := statusBarStyle.GetFrameSize()
_, h3 := statusBarMsgStyle.GetFrameSize()

tlIndex := m.taskList.Index()
atlIndex := m.archivedTaskList.Index()
Expand Down Expand Up @@ -654,7 +655,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

_, h2 := headerStyle.GetFrameSize()
_, h3 := statusBarStyle.GetFrameSize()
_, h3 := statusBarMsgStyle.GetFrameSize()

var contextHeight int
if m.cfg.ListDensity == Compact {
Expand Down Expand Up @@ -693,9 +694,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

switch m.activeView {
case taskListView:
m.lastActiveList = activeTasks
m.activeTaskList = activeTasks
default:
m.lastActiveList = archivedTasks
m.activeTaskList = archivedTasks
}
m.lastActiveView = m.activeView
m.activeView = taskDetailsView
Expand All @@ -707,7 +708,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var t types.Task
var ok bool

switch m.lastActiveList {
switch m.activeTaskList {
case activeTasks:
m.taskList.CursorUp()
t, ok = m.taskList.SelectedItem().(types.Task)
Expand All @@ -730,7 +731,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var t types.Task
var ok bool

switch m.lastActiveList {
switch m.activeTaskList {
case activeTasks:
m.taskList.CursorDown()
t, ok = m.taskList.SelectedItem().(types.Task)
Expand Down Expand Up @@ -772,9 +773,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.contextBMList.SetItems(bmItems)
switch m.activeView {
case taskListView:
m.lastActiveList = activeTasks
m.activeTaskList = activeTasks
case archivedTaskListView:
m.lastActiveList = archivedTasks
m.activeTaskList = archivedTasks
}
m.lastActiveView = m.activeView
m.activeView = contextBookmarksView
Expand Down Expand Up @@ -807,6 +808,39 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
for _, url := range urls {
cmds = append(cmds, openURL(url))
}

case "y":
if m.activeView != taskListView && m.activeView != archivedTaskListView && m.activeView != taskDetailsView {
break
}

var t types.Task
var ok bool

switch m.activeView {
case taskListView:
t, ok = m.taskList.SelectedItem().(types.Task)
case archivedTaskListView:
t, ok = m.archivedTaskList.SelectedItem().(types.Task)
case taskDetailsView:
switch m.activeTaskList {
case activeTasks:
t, ok = m.taskList.SelectedItem().(types.Task)
case archivedTasks:
t, ok = m.archivedTaskList.SelectedItem().(types.Task)
}
}

if !ok {
break
}

if t.Context == nil {
m.errorMsg = "There's no context to copy"
break
}

cmds = append(cmds, copyContextToClipboard(*t.Context))
}

case HideHelpMsg:
Expand Down Expand Up @@ -996,7 +1030,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
break
}

cmds = append(cmds, updateTaskContext(m.db, msg.taskIndex, msg.taskId, string(context), m.lastActiveList))
cmds = append(cmds, updateTaskContext(m.db, msg.taskIndex, msg.taskId, string(context), m.activeTaskList))
case urlOpenedMsg:
if msg.err != nil {
m.errorMsg = fmt.Sprintf("Error opening url: %s", msg.err)
Expand All @@ -1005,6 +1039,13 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if msg.err != nil {
m.errorMsg = fmt.Sprintf("Error opening urls: %s", msg.err)
}

case contextWrittenToCBMsg:
if msg.err != nil {
m.errorMsg = fmt.Sprintf("Couldn't copy context to clipboard: %s", msg.err)
} else {
m.successMsg = "Context copied to clipboard!"
}
}

if m.cfg.ListDensity == Compact {
Expand Down Expand Up @@ -1127,7 +1168,7 @@ func (m model) getContextUrls() ([]string, bool) {
case archivedTaskListView:
t, ok = m.archivedTaskList.SelectedItem().(types.Task)
case taskDetailsView:
switch m.lastActiveList {
switch m.activeTaskList {
case activeTasks:
t, ok = m.taskList.SelectedItem().(types.Task)
case archivedTasks:
Expand Down
16 changes: 12 additions & 4 deletions internal/ui/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"

"github.com/charmbracelet/lipgloss"
"github.com/dhth/omm/internal/utils"
)

var (
Expand All @@ -22,8 +23,15 @@ func (m model) View() string {
var helpMsg string
var listEmpty bool

if m.errorMsg != "" {
statusBar = m.errorMsg
if m.errorMsg != "" && m.successMsg != "" {
statusBar = fmt.Sprintf("%s%s",
sBErrMsgStyle.Render(utils.Trim(m.errorMsg, (m.terminalWidth/2)-3)),
sBSuccessMsgStyle.Render(utils.Trim(m.successMsg, (m.terminalWidth/2)-3)),
)
} else if m.errorMsg != "" {
statusBar = sBErrMsgStyle.Render(m.errorMsg)
} else if m.successMsg != "" {
statusBar = sBSuccessMsgStyle.Render(m.successMsg)
}

if m.showHelpIndicator && (m.activeView == taskListView || m.activeView == archivedTaskListView) {
Expand Down Expand Up @@ -117,7 +125,7 @@ func (m model) View() string {
context = taskDetailsStyle.Render(m.taskDetailsVP.View())
}

return lipgloss.JoinVertical(lipgloss.Left, headerStyle.Render(header), context, statusBarStyle.Render(statusBar))
return lipgloss.JoinVertical(lipgloss.Left, headerStyle.Render(header), context, statusBar)

case contextBookmarksView:
header = fmt.Sprintf("%s%s", contextBMTitleStyle.Render("Context Bookmarks"), helpMsg)
Expand Down Expand Up @@ -150,7 +158,7 @@ func (m model) View() string {
components = append(components, context)
}

components = append(components, statusBarStyle.Render(statusBar))
components = append(components, statusBar)

return lipgloss.JoinVertical(lipgloss.Left, components...)

Expand Down

0 comments on commit ae25b22

Please sign in to comment.