mirror of
https://github.com/charmbracelet/glow
synced 2025-01-06 00:58:45 +00:00
In a filter, deleting docs stashed in-session converts them to local ones
This commit is contained in:
parent
12f3209238
commit
2a688fc71e
6 changed files with 59 additions and 38 deletions
|
@ -17,7 +17,7 @@ import (
|
||||||
|
|
||||||
// markdown wraps charm.Markdown.
|
// markdown wraps charm.Markdown.
|
||||||
type markdown struct {
|
type markdown struct {
|
||||||
markdownType DocType
|
docType DocType
|
||||||
|
|
||||||
// Stash identifier. This exists so we can keep track of documents stashed
|
// Stash identifier. This exists so we can keep track of documents stashed
|
||||||
// in-session as they relate to their original, non-stashed counterparts.
|
// in-session as they relate to their original, non-stashed counterparts.
|
||||||
|
@ -34,6 +34,11 @@ type markdown struct {
|
||||||
// those that have been stashed in this session.
|
// those that have been stashed in this session.
|
||||||
localPath string
|
localPath string
|
||||||
|
|
||||||
|
// Modified time of the local file. This will also be stored in
|
||||||
|
// Markdown.CreatedAt, however we also retain it here incase we need to
|
||||||
|
// convert this document back to a local document after it's been stashed.
|
||||||
|
localModTime time.Time
|
||||||
|
|
||||||
// Value we filter against. This exists so that we can maintain positions
|
// Value we filter against. This exists so that we can maintain positions
|
||||||
// of filtered items if notes are edited while a filter is active. This
|
// of filtered items if notes are edited while a filter is active. This
|
||||||
// field is ephemeral, and should only be referenced during filtering.
|
// field is ephemeral, and should only be referenced during filtering.
|
||||||
|
@ -65,7 +70,7 @@ func (m *markdown) buildFilterValue() {
|
||||||
// shouldSortAsLocal returns whether or not this markdown should be sorted as though
|
// shouldSortAsLocal returns whether or not this markdown should be sorted as though
|
||||||
// it's a local markdown document.
|
// it's a local markdown document.
|
||||||
func (m markdown) shouldSortAsLocal() bool {
|
func (m markdown) shouldSortAsLocal() bool {
|
||||||
return m.markdownType == LocalDoc || m.markdownType == ConvertedDoc
|
return m.docType == LocalDoc || m.docType == ConvertedDoc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort documents with local files first, then by date.
|
// Sort documents with local files first, then by date.
|
||||||
|
@ -120,8 +125,8 @@ func normalize(in string) (string, error) {
|
||||||
func wrapMarkdowns(t DocType, md []*charm.Markdown) (m []*markdown) {
|
func wrapMarkdowns(t DocType, md []*charm.Markdown) (m []*markdown) {
|
||||||
for _, v := range md {
|
for _, v := range md {
|
||||||
m = append(m, &markdown{
|
m = append(m, &markdown{
|
||||||
markdownType: t,
|
docType: t,
|
||||||
Markdown: *v,
|
Markdown: *v,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
|
|
12
ui/pager.go
12
ui/pager.go
|
@ -212,8 +212,8 @@ func (m pagerModel) update(msg tea.Msg) (pagerModel, tea.Cmd) {
|
||||||
cmds = append(cmds, viewport.Sync(m.viewport))
|
cmds = append(cmds, viewport.Sync(m.viewport))
|
||||||
}
|
}
|
||||||
case "m":
|
case "m":
|
||||||
isStashed := m.currentDocument.markdownType == StashedDoc ||
|
isStashed := m.currentDocument.docType == StashedDoc ||
|
||||||
m.currentDocument.markdownType == ConvertedDoc
|
m.currentDocument.docType == ConvertedDoc
|
||||||
|
|
||||||
// Users can only set the note on user-stashed markdown
|
// Users can only set the note on user-stashed markdown
|
||||||
if !isStashed {
|
if !isStashed {
|
||||||
|
@ -249,7 +249,7 @@ func (m pagerModel) update(msg tea.Msg) (pagerModel, tea.Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stash a local document
|
// Stash a local document
|
||||||
if m.state != pagerStateStashing && stashableDocTypes.Contains(md.markdownType) {
|
if m.state != pagerStateStashing && stashableDocTypes.Contains(md.docType) {
|
||||||
m.state = pagerStateStashing
|
m.state = pagerStateStashing
|
||||||
m.spinner.Start()
|
m.spinner.Start()
|
||||||
cmds = append(
|
cmds = append(
|
||||||
|
@ -358,7 +358,7 @@ func (m pagerModel) statusBarView(b *strings.Builder) {
|
||||||
percentToStringMagnitude float64 = 100.0
|
percentToStringMagnitude float64 = 100.0
|
||||||
)
|
)
|
||||||
var (
|
var (
|
||||||
isStashed bool = m.currentDocument.markdownType == StashedDoc || m.currentDocument.markdownType == ConvertedDoc
|
isStashed bool = m.currentDocument.docType == StashedDoc || m.currentDocument.docType == ConvertedDoc
|
||||||
showStatusMessage bool = m.state == pagerStateStatusMessage
|
showStatusMessage bool = m.state == pagerStateStatusMessage
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -450,7 +450,7 @@ func (m pagerModel) setNoteView(b *strings.Builder) {
|
||||||
|
|
||||||
func (m pagerModel) helpView() (s string) {
|
func (m pagerModel) helpView() (s string) {
|
||||||
memoOrStash := "m set memo"
|
memoOrStash := "m set memo"
|
||||||
if m.common.authStatus == authOK && m.currentDocument.markdownType == LocalDoc {
|
if m.common.authStatus == authOK && m.currentDocument.docType == LocalDoc {
|
||||||
memoOrStash = "s stash this document"
|
memoOrStash = "s stash this document"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,7 +463,7 @@ func (m pagerModel) helpView() (s string) {
|
||||||
"q quit",
|
"q quit",
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.currentDocument.markdownType == NewsDoc {
|
if m.currentDocument.docType == NewsDoc {
|
||||||
deleteFromStringSlice(col1, 3)
|
deleteFromStringSlice(col1, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
49
ui/stash.go
49
ui/stash.go
|
@ -346,7 +346,7 @@ func (m stashModel) countMarkdowns(t DocType) (found int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(mds); i++ {
|
for i := 0; i < len(mds); i++ {
|
||||||
if mds[i].markdownType == t {
|
if mds[i].docType == t {
|
||||||
found++
|
found++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -363,7 +363,7 @@ func (m stashModel) getMarkdownByType(types ...DocType) []*markdown {
|
||||||
|
|
||||||
for _, t := range types {
|
for _, t := range types {
|
||||||
for _, md := range m.markdowns {
|
for _, md := range m.markdowns {
|
||||||
if md.markdownType == t {
|
if md.docType == t {
|
||||||
agg = append(agg, md)
|
agg = append(agg, md)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -401,7 +401,7 @@ func (m *stashModel) openMarkdown(md *markdown) tea.Cmd {
|
||||||
var cmd tea.Cmd
|
var cmd tea.Cmd
|
||||||
m.viewState = stashStateLoadingDocument
|
m.viewState = stashStateLoadingDocument
|
||||||
|
|
||||||
if md.markdownType == LocalDoc {
|
if md.docType == LocalDoc {
|
||||||
cmd = loadLocalMarkdown(md)
|
cmd = loadLocalMarkdown(md)
|
||||||
} else {
|
} else {
|
||||||
cmd = loadRemoteMarkdown(m.common.cc, md)
|
cmd = loadRemoteMarkdown(m.common.cc, md)
|
||||||
|
@ -783,7 +783,7 @@ func (m *stashModel) handleDocumentBrowsing(msg tea.Msg) tea.Cmd {
|
||||||
}
|
}
|
||||||
|
|
||||||
md := m.selectedMarkdown()
|
md := m.selectedMarkdown()
|
||||||
isUserMarkdown := md.markdownType == StashedDoc || md.markdownType == ConvertedDoc
|
isUserMarkdown := md.docType == StashedDoc || md.docType == ConvertedDoc
|
||||||
isSettingNote := m.selectionState == selectionSettingNote
|
isSettingNote := m.selectionState == selectionSettingNote
|
||||||
isPromptingDelete := m.selectionState == selectionPromptingDelete
|
isPromptingDelete := m.selectionState == selectionPromptingDelete
|
||||||
|
|
||||||
|
@ -803,7 +803,7 @@ func (m *stashModel) handleDocumentBrowsing(msg tea.Msg) tea.Cmd {
|
||||||
md := m.selectedMarkdown()
|
md := m.selectedMarkdown()
|
||||||
|
|
||||||
// Is this a document we're allowed to stash?
|
// Is this a document we're allowed to stash?
|
||||||
if !stashableDocTypes.Contains(md.markdownType) {
|
if !stashableDocTypes.Contains(md.docType) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -857,7 +857,7 @@ func (m *stashModel) handleDocumentBrowsing(msg tea.Msg) tea.Cmd {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
t := md.markdownType
|
t := md.docType
|
||||||
if t == StashedDoc || t == ConvertedDoc {
|
if t == StashedDoc || t == ConvertedDoc {
|
||||||
m.selectionState = selectionPromptingDelete
|
m.selectionState = selectionPromptingDelete
|
||||||
}
|
}
|
||||||
|
@ -914,7 +914,7 @@ func (m *stashModel) handleDeleteConfirmation(msg tea.Msg) tea.Cmd {
|
||||||
|
|
||||||
smd := m.selectedMarkdown()
|
smd := m.selectedMarkdown()
|
||||||
|
|
||||||
for i, md := range m.markdowns {
|
for _, md := range m.markdowns {
|
||||||
if md.uniqueID != smd.uniqueID {
|
if md.uniqueID != smd.uniqueID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -924,7 +924,7 @@ func (m *stashModel) handleDeleteConfirmation(msg tea.Msg) tea.Cmd {
|
||||||
|
|
||||||
// Delete optimistically and remove the stashed item before
|
// Delete optimistically and remove the stashed item before
|
||||||
// we've received a success response.
|
// we've received a success response.
|
||||||
mds, err := deleteMarkdown(m.markdowns, m.markdowns[i])
|
mds, err := deleteMarkdown(m.markdowns, md)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
m.markdowns = mds
|
m.markdowns = mds
|
||||||
}
|
}
|
||||||
|
@ -934,14 +934,29 @@ func (m *stashModel) handleDeleteConfirmation(msg tea.Msg) tea.Cmd {
|
||||||
|
|
||||||
// Also optimistically delete from filtered markdowns
|
// Also optimistically delete from filtered markdowns
|
||||||
if m.filterApplied() {
|
if m.filterApplied() {
|
||||||
for i, md := range m.filteredMarkdowns {
|
for _, md := range m.filteredMarkdowns {
|
||||||
if md.uniqueID != smd.uniqueID {
|
if md.uniqueID != smd.uniqueID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mds, err := deleteMarkdown(m.filteredMarkdowns, m.filteredMarkdowns[i])
|
|
||||||
if err == nil {
|
switch md.docType {
|
||||||
m.filteredMarkdowns = mds
|
|
||||||
|
// If the document was stashed in this session, convert it
|
||||||
|
// back to "local" document
|
||||||
|
case ConvertedDoc:
|
||||||
|
md.docType = LocalDoc
|
||||||
|
md.Note = stripAbsolutePath(md.localPath, m.common.cwd)
|
||||||
|
md.CreatedAt = md.localModTime
|
||||||
|
|
||||||
|
// Otherwise, remove the document from the listing
|
||||||
|
default:
|
||||||
|
mds, err := deleteMarkdown(m.filteredMarkdowns, md)
|
||||||
|
if err == nil {
|
||||||
|
m.filteredMarkdowns = mds
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1329,10 +1344,10 @@ func (m stashModel) populatedView() string {
|
||||||
// loadRemoteMarkdown is a command for loading markdown from the server.
|
// loadRemoteMarkdown is a command for loading markdown from the server.
|
||||||
func loadRemoteMarkdown(cc *charm.Client, md *markdown) tea.Cmd {
|
func loadRemoteMarkdown(cc *charm.Client, md *markdown) tea.Cmd {
|
||||||
return func() tea.Msg {
|
return func() tea.Msg {
|
||||||
newMD, err := fetchMarkdown(cc, md.ID, md.markdownType)
|
newMD, err := fetchMarkdown(cc, md.ID, md.docType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if debug {
|
if debug {
|
||||||
log.Printf("error loading %s markdown (ID %d, Note: '%s'): %v", md.markdownType, md.ID, md.Note, err)
|
log.Printf("error loading %s markdown (ID %d, Note: '%s'): %v", md.docType, md.ID, md.Note, err)
|
||||||
}
|
}
|
||||||
return markdownFetchFailedMsg{
|
return markdownFetchFailedMsg{
|
||||||
err: err,
|
err: err,
|
||||||
|
@ -1347,7 +1362,7 @@ func loadRemoteMarkdown(cc *charm.Client, md *markdown) tea.Cmd {
|
||||||
|
|
||||||
func loadLocalMarkdown(md *markdown) tea.Cmd {
|
func loadLocalMarkdown(md *markdown) tea.Cmd {
|
||||||
return func() tea.Msg {
|
return func() tea.Msg {
|
||||||
if md.markdownType != LocalDoc {
|
if md.docType != LocalDoc {
|
||||||
return errMsg{errors.New("could not load local file: not a local file")}
|
return errMsg{errors.New("could not load local file: not a local file")}
|
||||||
}
|
}
|
||||||
if md.localPath == "" {
|
if md.localPath == "" {
|
||||||
|
@ -1425,8 +1440,8 @@ func fetchMarkdown(cc *charm.Client, id int, t DocType) (*markdown, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &markdown{
|
return &markdown{
|
||||||
markdownType: t,
|
docType: t,
|
||||||
Markdown: *md,
|
Markdown: *md,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,8 +120,8 @@ func (m stashModel) helpView() (string, int) {
|
||||||
|
|
||||||
if numDocs > 0 {
|
if numDocs > 0 {
|
||||||
md := m.selectedMarkdown()
|
md := m.selectedMarkdown()
|
||||||
isStashed = md != nil && md.markdownType == StashedDoc
|
isStashed = md != nil && md.docType == StashedDoc
|
||||||
isStashable = md != nil && md.markdownType == LocalDoc && m.online()
|
isStashable = md != nil && md.docType == LocalDoc && m.online()
|
||||||
}
|
}
|
||||||
|
|
||||||
if numDocs > 0 && m.showFullHelp {
|
if numDocs > 0 && m.showFullHelp {
|
||||||
|
|
|
@ -27,7 +27,7 @@ func stashItemView(b *strings.Builder, m stashModel, index int, md *markdown) {
|
||||||
icon = ""
|
icon = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
switch md.markdownType {
|
switch md.docType {
|
||||||
case NewsDoc:
|
case NewsDoc:
|
||||||
if title == "" {
|
if title == "" {
|
||||||
title = "News"
|
title = "News"
|
||||||
|
@ -81,7 +81,7 @@ func stashItemView(b *strings.Builder, m stashModel, index int, md *markdown) {
|
||||||
} else {
|
} else {
|
||||||
// Regular (non-selected) items
|
// Regular (non-selected) items
|
||||||
|
|
||||||
if md.markdownType == NewsDoc {
|
if md.docType == NewsDoc {
|
||||||
gutter = " "
|
gutter = " "
|
||||||
|
|
||||||
if isFiltering && m.filterInput.Value() == "" {
|
if isFiltering && m.filterInput.Value() == "" {
|
||||||
|
|
15
ui/ui.go
15
ui/ui.go
|
@ -412,7 +412,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
|
|
||||||
if m.stash.filterApplied() {
|
if m.stash.filterApplied() {
|
||||||
for _, v := range m.stash.filteredMarkdowns {
|
for _, v := range m.stash.filteredMarkdowns {
|
||||||
if v.stashID == msg.stashID && v.markdownType == ConvertedDoc {
|
if v.stashID == msg.stashID && v.docType == ConvertedDoc {
|
||||||
// Add the server-side ID we got back so we can do things
|
// Add the server-side ID we got back so we can do things
|
||||||
// like rename and stash it.
|
// like rename and stash it.
|
||||||
v.ID = msg.ID
|
v.ID = msg.ID
|
||||||
|
@ -658,7 +658,7 @@ func stashDocument(cc *charm.Client, md markdown) tea.Cmd {
|
||||||
// be loaded. But...if it turnsout the document body really is empty
|
// be loaded. But...if it turnsout the document body really is empty
|
||||||
// then we'll stash it anyway.
|
// then we'll stash it anyway.
|
||||||
if len(md.Body) == 0 {
|
if len(md.Body) == 0 {
|
||||||
switch md.markdownType {
|
switch md.docType {
|
||||||
|
|
||||||
case LocalDoc:
|
case LocalDoc:
|
||||||
data, err := ioutil.ReadFile(md.localPath)
|
data, err := ioutil.ReadFile(md.localPath)
|
||||||
|
@ -671,14 +671,14 @@ func stashDocument(cc *charm.Client, md markdown) tea.Cmd {
|
||||||
md.Body = string(data)
|
md.Body = string(data)
|
||||||
|
|
||||||
case NewsDoc:
|
case NewsDoc:
|
||||||
newMD, err := fetchMarkdown(cc, md.ID, md.markdownType)
|
newMD, err := fetchMarkdown(cc, md.ID, md.docType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return stashFailMsg{err, md}
|
return stashFailMsg{err, md}
|
||||||
}
|
}
|
||||||
md.Body = newMD.Body
|
md.Body = newMD.Body
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err := fmt.Errorf("user is attempting to stash an unsupported markdown type: %s", md.markdownType)
|
err := fmt.Errorf("user is attempting to stash an unsupported markdown type: %s", md.docType)
|
||||||
if debug {
|
if debug {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
|
@ -719,8 +719,9 @@ func waitForStatusMessageTimeout(appCtx applicationContext, t *time.Timer) tea.C
|
||||||
// a directory, but we trust that gitcha has already done that.
|
// a directory, but we trust that gitcha has already done that.
|
||||||
func localFileToMarkdown(cwd string, res gitcha.SearchResult) *markdown {
|
func localFileToMarkdown(cwd string, res gitcha.SearchResult) *markdown {
|
||||||
md := &markdown{
|
md := &markdown{
|
||||||
markdownType: LocalDoc,
|
docType: LocalDoc,
|
||||||
localPath: res.Path,
|
localPath: res.Path,
|
||||||
|
localModTime: res.Info.ModTime(),
|
||||||
Markdown: charm.Markdown{
|
Markdown: charm.Markdown{
|
||||||
Note: stripAbsolutePath(res.Path, cwd),
|
Note: stripAbsolutePath(res.Path, cwd),
|
||||||
CreatedAt: res.Info.ModTime(),
|
CreatedAt: res.Info.ModTime(),
|
||||||
|
@ -734,11 +735,11 @@ func localFileToMarkdown(cwd string, res gitcha.SearchResult) *markdown {
|
||||||
// that occur as part of stashing.
|
// that occur as part of stashing.
|
||||||
func convertMarkdownToStashed(md *markdown) {
|
func convertMarkdownToStashed(md *markdown) {
|
||||||
// Set the note as the filename without the extension
|
// Set the note as the filename without the extension
|
||||||
if md.markdownType == LocalDoc {
|
if md.docType == LocalDoc {
|
||||||
md.Note = strings.Replace(path.Base(md.localPath), path.Ext(md.localPath), "", 1)
|
md.Note = strings.Replace(path.Base(md.localPath), path.Ext(md.localPath), "", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
md.markdownType = ConvertedDoc
|
md.docType = ConvertedDoc
|
||||||
md.CreatedAt = time.Now()
|
md.CreatedAt = time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue