Press [ in detail view to open link picker showing all [[links]] in the current entry. Enter follows a link, resolving by title then body substring. Navigation history stack enables esc to pop back through followed links before returning to list. Adds Store.ResolveLink() for non-transactional link resolution from the TUI layer.
This commit is contained in:
@@ -24,6 +24,7 @@ const (
|
||||
statePromote
|
||||
stateAbsorb
|
||||
stateStumble
|
||||
stateLinkPicker
|
||||
)
|
||||
|
||||
type viewMode int
|
||||
@@ -90,6 +91,8 @@ type model struct {
|
||||
stumble stumbleModel
|
||||
showHelp bool
|
||||
autocomplete autocompleteModel
|
||||
linkPicker linkPickerModel
|
||||
navStack []string
|
||||
|
||||
focus focusPane
|
||||
splitDetail bool
|
||||
@@ -293,6 +296,11 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
return m, nil
|
||||
|
||||
case linkFollowedMsg:
|
||||
m.detail.setEntity(msg.entity)
|
||||
m.state = stateDetail
|
||||
return m, loadBacklinks(m.store, msg.entity.ID)
|
||||
|
||||
case tagsLoadedMsg:
|
||||
m.filter.setTags(msg.tags)
|
||||
m.tagRail.setTags(msg.tags)
|
||||
@@ -346,6 +354,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
return m.updateAbsorb(msg)
|
||||
case stateStumble:
|
||||
return m.updateStumble(msg)
|
||||
case stateLinkPicker:
|
||||
return m.updateLinkPicker(msg)
|
||||
default:
|
||||
return m.updateKeys(msg)
|
||||
}
|
||||
@@ -717,6 +727,19 @@ func (m model) updateBrowse(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
if len(m.navStack) > 0 {
|
||||
prevID := m.navStack[len(m.navStack)-1]
|
||||
m.navStack = m.navStack[:len(m.navStack)-1]
|
||||
return m, tea.Batch(
|
||||
func() tea.Msg {
|
||||
e, err := m.store.Get(context.Background(), prevID)
|
||||
if err != nil {
|
||||
return errMsg{err}
|
||||
}
|
||||
return linkFollowedMsg{e}
|
||||
},
|
||||
)
|
||||
}
|
||||
if m.isSplit() {
|
||||
m.state = stateList
|
||||
m.splitDetail = true
|
||||
@@ -835,6 +858,14 @@ func (m model) updateBrowse(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
return m, nil
|
||||
|
||||
case "[":
|
||||
if m.state == stateDetail && m.detail.entity != nil && m.detail.mode == detailPreview {
|
||||
m.linkPicker = newLinkPicker(m.detail.entity.Body)
|
||||
m.state = stateLinkPicker
|
||||
return m, nil
|
||||
}
|
||||
return m, nil
|
||||
|
||||
case "r":
|
||||
if m.state == stateDetail && m.detail.entity != nil && m.detail.mode == detailPreview {
|
||||
if m.detail.entity.CardType != nil && *m.detail.entity.CardType == db.CardChecklist {
|
||||
@@ -927,6 +958,26 @@ func (m model) updateConfirm(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m model) updateLinkPicker(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
switch msg.String() {
|
||||
case "esc", "q":
|
||||
m.state = stateDetail
|
||||
return m, nil
|
||||
case "enter":
|
||||
lt := m.linkPicker.selected()
|
||||
if lt == "" {
|
||||
return m, nil
|
||||
}
|
||||
if m.detail.entity != nil {
|
||||
m.navStack = append(m.navStack, m.detail.entity.ID)
|
||||
}
|
||||
return m, followLink(m.store, lt)
|
||||
default:
|
||||
m.linkPicker = m.linkPicker.update(msg.String())
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (m model) updatePromote(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
switch msg.String() {
|
||||
case "esc", "q":
|
||||
@@ -1045,6 +1096,8 @@ func (m model) View() string {
|
||||
content = m.absorb.view(m.width)
|
||||
case stateStumble:
|
||||
content = m.stumble.view()
|
||||
case stateLinkPicker:
|
||||
content = m.linkPicker.view(m.width)
|
||||
}
|
||||
|
||||
header := m.headerView()
|
||||
|
||||
Reference in New Issue
Block a user