diff --git a/internal/markdown/markdown.go b/internal/markdown/markdown.go deleted file mode 100644 index 86a31dc..0000000 --- a/internal/markdown/markdown.go +++ /dev/null @@ -1,57 +0,0 @@ -package markdown - -import ( - "github.com/knipferrc/fm/strfmt" - - "github.com/charmbracelet/glamour" - "github.com/charmbracelet/lipgloss" -) - -// Model contains the properties of markdown. -type Model struct { - Content string - Width int -} - -// RenderMarkdown renders the markdown content with glamour. -func RenderMarkdown(width int, content string) (string, error) { - bg := "light" - - if lipgloss.HasDarkBackground() { - bg = "dark" - } - - r, _ := glamour.NewTermRenderer( - glamour.WithWordWrap(width), - glamour.WithStandardStyle(bg), - ) - - out, err := r.Render(content) - if err != nil { - return "", err - } - - return out, nil -} - -// SetContent sets the markdown content. -func (m *Model) SetContent(content string) { - m.Content = content -} - -// GetContent returns the markdown content. -func (m Model) GetContent() string { - return m.Content -} - -// SetSize sets the width of the markdown. -func (m *Model) SetSize(width int) { - m.Width = width -} - -// View returns a string representation of the markdown. -func (m Model) View() string { - return lipgloss.NewStyle().Width(m.Width).Render( - strfmt.ConvertTabsToSpaces(m.Content), - ) -} diff --git a/internal/pdfdoc/pdfdoc.go b/internal/pdfdoc/pdfdoc.go deleted file mode 100644 index b127bd0..0000000 --- a/internal/pdfdoc/pdfdoc.go +++ /dev/null @@ -1,62 +0,0 @@ -package pdfdoc - -import ( - "bytes" - - "github.com/knipferrc/fm/strfmt" - - "github.com/charmbracelet/lipgloss" - "github.com/ledongthuc/pdf" -) - -// Model represents the properties of text. -type Model struct { - Content string - Width int -} - -// ReadPdf reads a PDF file given a name. -func ReadPdf(name string) (string, error) { - f, r, err := pdf.Open(name) - if err != nil { - return "", err - } - - defer f.Close() - - buf := new(bytes.Buffer) - b, err := r.GetPlainText() - - if err != nil { - return "", err - } - - _, err = buf.ReadFrom(b) - if err != nil { - return "", err - } - - return buf.String(), nil -} - -// SetSize sets the size of the pdfdoc. -func (m *Model) SetSize(width int) { - m.Width = width -} - -// SetContent sets the content of the pdfdoc. -func (m *Model) SetContent(content string) { - m.Content = content -} - -// GetContent returns the content of the pdfdoc. -func (m Model) GetContent() string { - return m.Content -} - -// View returns a string representation of pdfdoc. -func (m *Model) View() string { - return lipgloss.NewStyle(). - Width(m.Width). - Render(strfmt.ConvertTabsToSpaces(m.Content)) -} diff --git a/internal/colorimage/colorimage.go b/internal/renderer/renderer.go similarity index 56% rename from internal/colorimage/colorimage.go rename to internal/renderer/renderer.go index b5b0e94..7f2f850 100644 --- a/internal/colorimage/colorimage.go +++ b/internal/renderer/renderer.go @@ -1,11 +1,15 @@ -package colorimage +package renderer import ( + "bytes" "image" "strings" + "github.com/alecthomas/chroma/quick" + "github.com/charmbracelet/glamour" "github.com/charmbracelet/lipgloss" "github.com/disintegration/imaging" + "github.com/ledongthuc/pdf" "github.com/lucasb-eyer/go-colorful" ) @@ -44,6 +48,61 @@ func ImageToString(width int, img image.Image) string { return str.String() } +// RenderMarkdown renders the markdown content with glamour. +func RenderMarkdown(width int, content string) (string, error) { + bg := "light" + + if lipgloss.HasDarkBackground() { + bg = "dark" + } + + r, _ := glamour.NewTermRenderer( + glamour.WithWordWrap(width), + glamour.WithStandardStyle(bg), + ) + + out, err := r.Render(content) + if err != nil { + return "", err + } + + return out, nil +} + +// ReadPdf reads a PDF file given a name. +func ReadPdf(name string) (string, error) { + f, r, err := pdf.Open(name) + if err != nil { + return "", err + } + + defer f.Close() + + buf := new(bytes.Buffer) + b, err := r.GetPlainText() + + if err != nil { + return "", err + } + + _, err = buf.ReadFrom(b) + if err != nil { + return "", err + } + + return buf.String(), nil +} + +// Highlight returns a syntax highlighted string of text. +func Highlight(content, extension, syntaxTheme string) (string, error) { + buf := new(bytes.Buffer) + if err := quick.Highlight(buf, content, extension, "terminal256", syntaxTheme); err != nil { + return "", err + } + + return buf.String(), nil +} + // SetSize sets the size of the colorimage. func (m *Model) SetSize(width int) { m.Width = width @@ -69,6 +128,11 @@ func (m Model) GetWidth() int { return m.Width } +// GetContent returns the content of the renderer. +func (m Model) GetContent() string { + return m.Content +} + // View returns a string representation of a colorimage. func (m Model) View() string { return lipgloss.NewStyle().Width(m.Width).Render(m.Content) diff --git a/internal/text/text.go b/internal/text/text.go deleted file mode 100644 index 42cf2d4..0000000 --- a/internal/text/text.go +++ /dev/null @@ -1,48 +0,0 @@ -package text - -import ( - "bytes" - - "github.com/knipferrc/fm/strfmt" - - "github.com/alecthomas/chroma/quick" - "github.com/charmbracelet/lipgloss" -) - -// Model represents the properties of text. -type Model struct { - Content string - Width int -} - -// Highlight returns a syntax highlighted string of text. -func Highlight(content, extension, syntaxTheme string) (string, error) { - buf := new(bytes.Buffer) - if err := quick.Highlight(buf, content, extension, "terminal256", syntaxTheme); err != nil { - return "", err - } - - return buf.String(), nil -} - -// SetSize sets the size of the text. -func (m *Model) SetSize(width int) { - m.Width = width -} - -// SetContent sets the content of the text. -func (m *Model) SetContent(content string) { - m.Content = content -} - -// GetContent returns the content of the text. -func (m Model) GetContent() string { - return m.Content -} - -// View returns a string representation of text. -func (m *Model) View() string { - return lipgloss.NewStyle(). - Width(m.Width). - Render(strfmt.ConvertTabsToSpaces(m.Content)) -} diff --git a/internal/ui/commands.go b/internal/ui/commands.go index 6d74b82..7615858 100644 --- a/internal/ui/commands.go +++ b/internal/ui/commands.go @@ -15,10 +15,7 @@ import ( _ "image/png" "github.com/knipferrc/fm/dirfs" - "github.com/knipferrc/fm/internal/colorimage" - "github.com/knipferrc/fm/internal/markdown" - "github.com/knipferrc/fm/internal/pdfdoc" - "github.com/knipferrc/fm/internal/text" + "github.com/knipferrc/fm/internal/renderer" "github.com/knipferrc/fm/strfmt" tea "github.com/charmbracelet/bubbletea" @@ -118,7 +115,7 @@ func (m Model) moveDirectoryItemCmd(name string) tea.Cmd { // redrawImageCmd redraws the image based on the width provided. func (m Model) redrawImageCmd(width int) tea.Cmd { return func() tea.Msg { - imageString := colorimage.ImageToString(width, m.colorimage.Image) + imageString := renderer.ImageToString(width, m.renderer.Image) return convertImageToStringMsg(imageString) } @@ -156,7 +153,7 @@ func (m Model) readFileContentCmd(file os.FileInfo, width int) tea.Cmd { switch { case filepath.Ext(file.Name()) == ".md" && m.appConfig.Settings.PrettyMarkdown: - markdownContent, err := markdown.RenderMarkdown(width, content) + markdownContent, err := renderer.RenderMarkdown(width, content) if err != nil { return errorMsg(err.Error()) } @@ -180,7 +177,7 @@ func (m Model) readFileContentCmd(file os.FileInfo, width int) tea.Cmd { return errorMsg(err.Error()) } - imageString := colorimage.ImageToString(width, img) + imageString := renderer.ImageToString(width, img) return readFileContentMsg{ rawContent: content, @@ -191,7 +188,7 @@ func (m Model) readFileContentCmd(file os.FileInfo, width int) tea.Cmd { image: img, } case filepath.Ext(file.Name()) == ".pdf": - pdfContent, err := pdfdoc.ReadPdf(file.Name()) + pdfContent, err := renderer.ReadPdf(file.Name()) if err != nil { return errorMsg(err.Error()) } @@ -205,7 +202,7 @@ func (m Model) readFileContentCmd(file os.FileInfo, width int) tea.Cmd { image: nil, } default: - code, err := text.Highlight(content, filepath.Ext(file.Name()), m.appConfig.Settings.SyntaxTheme) + code, err := renderer.Highlight(content, filepath.Ext(file.Name()), m.appConfig.Settings.SyntaxTheme) if err != nil { return errorMsg(err.Error()) } diff --git a/internal/ui/model.go b/internal/ui/model.go index 02cefca..e4ec7a9 100644 --- a/internal/ui/model.go +++ b/internal/ui/model.go @@ -4,14 +4,11 @@ import ( "context" "os" - "github.com/knipferrc/fm/internal/colorimage" "github.com/knipferrc/fm/internal/config" "github.com/knipferrc/fm/internal/dirtree" - "github.com/knipferrc/fm/internal/markdown" "github.com/knipferrc/fm/internal/pane" - "github.com/knipferrc/fm/internal/pdfdoc" + "github.com/knipferrc/fm/internal/renderer" "github.com/knipferrc/fm/internal/statusbar" - "github.com/knipferrc/fm/internal/text" "github.com/knipferrc/fm/internal/theme" "github.com/charmbracelet/bubbles/help" @@ -34,10 +31,7 @@ type Model struct { dirTree dirtree.Model dirTreePreview dirtree.Model statusBar statusbar.Model - colorimage colorimage.Model - markdown markdown.Model - text text.Model - pdfdoc pdfdoc.Model + renderer renderer.Model itemToMove os.FileInfo appConfig config.Config directoryItemSizeCtx *directoryItemSizeCtx @@ -129,10 +123,7 @@ func NewModel() Model { dirTree: dirTree, dirTreePreview: dirTreePreview, statusBar: statusBar, - colorimage: colorimage.Model{}, - markdown: markdown.Model{}, - text: text.Model{}, - pdfdoc: pdfdoc.Model{}, + renderer: renderer.Model{}, itemToMove: nil, appConfig: cfg, directoryItemSizeCtx: &directoryItemSizeCtx{ diff --git a/internal/ui/update.go b/internal/ui/update.go index 0984086..f52eda3 100644 --- a/internal/ui/update.go +++ b/internal/ui/update.go @@ -86,9 +86,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.createDirectoryMode = false m.renameMode = false - m.markdown.SetContent("") - m.text.SetContent("") - m.colorimage.SetImage(nil) + m.renderer.SetContent("") + m.renderer.SetImage(nil) m.dirTreePreview.GotoTop() m.dirTreePreview.SetContent(msg) m.secondaryPane.SetContent(m.dirTreePreview.View()) @@ -116,37 +115,28 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch { case msg.code != "": m.secondaryPane.GotoTop() - m.colorimage.SetImage(nil) - m.markdown.SetContent("") m.dirTreePreview.SetContent(nil) - m.text.SetContent(msg.code) - m.pdfdoc.SetContent("") - m.secondaryPane.SetContent(m.text.View()) + m.renderer.SetContent(msg.code) + m.renderer.SetImage(nil) + m.secondaryPane.SetContent(m.renderer.View()) case msg.pdfContent != "": m.secondaryPane.GotoTop() - m.colorimage.SetImage(nil) - m.markdown.SetContent("") m.dirTreePreview.SetContent(nil) - m.text.SetContent("") - m.pdfdoc.SetContent(msg.pdfContent) - m.secondaryPane.SetContent(m.pdfdoc.View()) + m.renderer.SetContent(msg.pdfContent) + m.renderer.SetImage(nil) + m.secondaryPane.SetContent(m.renderer.View()) case msg.markdown != "": m.secondaryPane.GotoTop() - m.colorimage.SetImage(nil) - m.text.SetContent("") + m.renderer.SetImage(nil) m.dirTreePreview.SetContent(nil) - m.markdown.SetContent(msg.markdown) - m.pdfdoc.SetContent("") - m.secondaryPane.SetContent(m.markdown.View()) + m.renderer.SetContent(msg.markdown) + m.secondaryPane.SetContent(m.renderer.View()) case msg.image != nil: m.secondaryPane.GotoTop() - m.markdown.SetContent("") - m.text.SetContent("") m.dirTreePreview.SetContent(nil) - m.pdfdoc.SetContent("") - m.colorimage.SetImage(msg.image) - m.colorimage.SetContent(msg.imageString) - m.secondaryPane.SetContent(m.colorimage.View()) + m.renderer.SetImage(msg.image) + m.renderer.SetContent(msg.imageString) + m.secondaryPane.SetContent(m.renderer.View()) default: m.secondaryPane.GotoTop() m.secondaryPane.SetContent(msg.rawContent) @@ -156,8 +146,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // convertImageToStringMsg is received when an image is to be converted to a string. case convertImageToStringMsg: - m.colorimage.SetContent(string(msg)) - m.secondaryPane.SetContent(m.colorimage.View()) + m.renderer.SetContent(string(msg)) + m.secondaryPane.SetContent(m.renderer.View()) return m, nil @@ -181,8 +171,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // copyToClipboardMsg when the selected directory item is copyied to the clipboard. case copyToClipboardMsg: - m.text.SetContent(string(msg)) - m.secondaryPane.SetContent(m.text.View()) + m.renderer.SetContent(string(msg)) + m.secondaryPane.SetContent(m.renderer.View()) return m, nil @@ -192,31 +182,22 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.secondaryPane.SetSize(msg.Width/2, msg.Height-m.statusBar.GetHeight()) m.dirTree.SetSize(m.primaryPane.GetWidth()) m.dirTreePreview.SetSize(m.secondaryPane.GetWidth()) - m.text.SetSize(m.secondaryPane.GetWidth() - m.secondaryPane.GetHorizontalFrameSize()) - m.markdown.SetSize(m.secondaryPane.GetWidth() - m.secondaryPane.GetHorizontalFrameSize()) - m.colorimage.SetSize(m.secondaryPane.GetWidth() - m.secondaryPane.GetHorizontalFrameSize()) - m.pdfdoc.SetSize(m.secondaryPane.GetWidth() - m.secondaryPane.GetHorizontalFrameSize()) + m.renderer.SetSize(m.secondaryPane.GetWidth() - m.secondaryPane.GetHorizontalFrameSize()) m.primaryPane.SetContent(m.dirTree.View()) m.help.Width = msg.Width switch { - case m.colorimage.GetImage() != nil: - cmds = append(cmds, m.redrawImageCmd(m.colorimage.GetWidth())) - case m.markdown.GetContent() != "": - m.secondaryPane.SetContent(m.markdown.View()) - case m.text.GetContent() != "": - m.secondaryPane.SetContent(m.text.View()) + case m.renderer.GetImage() != nil: + cmds = append(cmds, m.redrawImageCmd(m.renderer.GetWidth())) + case m.renderer.GetContent() != "": + m.secondaryPane.SetContent(m.renderer.View()) case m.dirTreePreview.GetTotalFiles() != 0: m.secondaryPane.SetContent(m.dirTreePreview.View()) - case m.pdfdoc.GetContent() != "": - m.secondaryPane.SetContent(m.pdfdoc.View()) - case m.text.GetContent() == "" && m.markdown.GetContent() == "" && m.colorimage.GetImage() == nil && m.dirTreePreview.GetTotalFiles() == 0 && m.pdfdoc.GetContent() == "": + case m.renderer.GetContent() == "" && m.dirTreePreview.GetTotalFiles() == 0: m.secondaryPane.SetContent(lipgloss.NewStyle(). Width(m.secondaryPane.GetWidth() - m.secondaryPane.GetHorizontalFrameSize()). Render(m.help.View(m.keys)), ) - default: - return m, nil } if !m.ready { @@ -611,10 +592,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { Width(m.secondaryPane.GetWidth() - m.secondaryPane.Style.GetHorizontalFrameSize()). Render(m.help.View(m.keys)), ) - m.colorimage.SetImage(nil) - m.markdown.SetContent("") - m.text.SetContent("") - m.pdfdoc.SetContent("") + m.renderer.SetImage(nil) + m.renderer.SetContent("") m.dirTreePreview.SetContent(nil) m.updateStatusBarContent() }