mirror of
https://github.com/RWejlgaard/org.git
synced 2026-05-06 04:34:45 +00:00
fix: word-wrapping on notes when terminal is small (#8)
This commit is contained in:
parent
aaa0ad0f55
commit
5a6fede2d8
2 changed files with 130 additions and 5 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
package ui
|
package ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/charmbracelet/bubbles/help"
|
"github.com/charmbracelet/bubbles/help"
|
||||||
|
|
@ -104,8 +105,13 @@ func (m *uiModel) updateScrollOffset(availableHeight int) {
|
||||||
for i, item := range items {
|
for i, item := range items {
|
||||||
lineCount := 1 // The item itself
|
lineCount := 1 // The item itself
|
||||||
if !item.Folded && len(item.Notes) > 0 && m.mode == modeList {
|
if !item.Folded && len(item.Notes) > 0 && m.mode == modeList {
|
||||||
// Count note lines (simplified - just count notes)
|
// Count note lines with wrapping
|
||||||
lineCount += len(item.Notes)
|
indent := strings.Repeat(" ", item.Level)
|
||||||
|
noteIndent := indent + " "
|
||||||
|
filteredNotes := filterLogbookDrawer(item.Notes)
|
||||||
|
wrappedNotes := wrapNoteLines(filteredNotes, m.width, noteIndent)
|
||||||
|
highlightedNotes := renderNotesWithHighlighting(wrappedNotes)
|
||||||
|
lineCount += len(highlightedNotes)
|
||||||
}
|
}
|
||||||
itemLineCount[i] = lineCount
|
itemLineCount[i] = lineCount
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -146,8 +146,11 @@ func (m uiModel) View() string {
|
||||||
for i, item := range items {
|
for i, item := range items {
|
||||||
lineCount := 1 // The item itself
|
lineCount := 1 // The item itself
|
||||||
if !item.Folded && len(item.Notes) > 0 && m.mode == modeList {
|
if !item.Folded && len(item.Notes) > 0 && m.mode == modeList {
|
||||||
|
indent := strings.Repeat(" ", item.Level)
|
||||||
|
noteIndent := indent + " "
|
||||||
filteredNotes := filterLogbookDrawer(item.Notes)
|
filteredNotes := filterLogbookDrawer(item.Notes)
|
||||||
highlightedNotes := renderNotesWithHighlighting(filteredNotes)
|
wrappedNotes := wrapNoteLines(filteredNotes, m.width, noteIndent)
|
||||||
|
highlightedNotes := renderNotesWithHighlighting(wrappedNotes)
|
||||||
lineCount += len(highlightedNotes)
|
lineCount += len(highlightedNotes)
|
||||||
}
|
}
|
||||||
itemLineCount[i] = lineCount
|
itemLineCount[i] = lineCount
|
||||||
|
|
@ -205,8 +208,10 @@ func (m uiModel) View() string {
|
||||||
// Render remaining notes
|
// Render remaining notes
|
||||||
if !item.Folded && len(item.Notes) > 0 && m.mode == modeList {
|
if !item.Folded && len(item.Notes) > 0 && m.mode == modeList {
|
||||||
indent := strings.Repeat(" ", item.Level)
|
indent := strings.Repeat(" ", item.Level)
|
||||||
|
noteIndent := indent + " "
|
||||||
filteredNotes := filterLogbookDrawer(item.Notes)
|
filteredNotes := filterLogbookDrawer(item.Notes)
|
||||||
highlightedNotes := renderNotesWithHighlighting(filteredNotes)
|
wrappedNotes := wrapNoteLines(filteredNotes, m.width, noteIndent)
|
||||||
|
highlightedNotes := renderNotesWithHighlighting(wrappedNotes)
|
||||||
for noteIdx := linesToSkip - 1; noteIdx < len(highlightedNotes) && itemLines < availableHeight; noteIdx++ {
|
for noteIdx := linesToSkip - 1; noteIdx < len(highlightedNotes) && itemLines < availableHeight; noteIdx++ {
|
||||||
content.WriteString(indent)
|
content.WriteString(indent)
|
||||||
content.WriteString(" " + highlightedNotes[noteIdx])
|
content.WriteString(" " + highlightedNotes[noteIdx])
|
||||||
|
|
@ -227,8 +232,10 @@ func (m uiModel) View() string {
|
||||||
// Show notes if not folded
|
// Show notes if not folded
|
||||||
if !item.Folded && len(item.Notes) > 0 && m.mode == modeList {
|
if !item.Folded && len(item.Notes) > 0 && m.mode == modeList {
|
||||||
indent := strings.Repeat(" ", item.Level)
|
indent := strings.Repeat(" ", item.Level)
|
||||||
|
noteIndent := indent + " "
|
||||||
filteredNotes := filterLogbookDrawer(item.Notes)
|
filteredNotes := filterLogbookDrawer(item.Notes)
|
||||||
highlightedNotes := renderNotesWithHighlighting(filteredNotes)
|
wrappedNotes := wrapNoteLines(filteredNotes, m.width, noteIndent)
|
||||||
|
highlightedNotes := renderNotesWithHighlighting(wrappedNotes)
|
||||||
for _, note := range highlightedNotes {
|
for _, note := range highlightedNotes {
|
||||||
if itemLines >= availableHeight {
|
if itemLines >= availableHeight {
|
||||||
break
|
break
|
||||||
|
|
@ -610,6 +617,29 @@ func filterLogbookDrawer(notes []string) []string {
|
||||||
return filtered
|
return filtered
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wrapNoteLines wraps note lines to fit within the specified width
|
||||||
|
func wrapNoteLines(notes []string, width int, indent string) []string {
|
||||||
|
var wrapped []string
|
||||||
|
for _, note := range notes {
|
||||||
|
// Don't wrap code block delimiters or drawer markers
|
||||||
|
trimmed := strings.TrimSpace(note)
|
||||||
|
if strings.HasPrefix(trimmed, "#+BEGIN_SRC") ||
|
||||||
|
strings.HasPrefix(trimmed, "#+END_SRC") ||
|
||||||
|
strings.HasPrefix(trimmed, "```") ||
|
||||||
|
trimmed == ":LOGBOOK:" ||
|
||||||
|
trimmed == ":PROPERTIES:" ||
|
||||||
|
trimmed == ":END:" {
|
||||||
|
wrapped = append(wrapped, note)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap the note line
|
||||||
|
wrappedLines := wrapText(note, width, indent)
|
||||||
|
wrapped = append(wrapped, wrappedLines...)
|
||||||
|
}
|
||||||
|
return wrapped
|
||||||
|
}
|
||||||
|
|
||||||
// renderNotesWithHighlighting renders notes with syntax highlighting for code blocks
|
// renderNotesWithHighlighting renders notes with syntax highlighting for code blocks
|
||||||
func renderNotesWithHighlighting(notes []string) []string {
|
func renderNotesWithHighlighting(notes []string) []string {
|
||||||
if len(notes) == 0 {
|
if len(notes) == 0 {
|
||||||
|
|
@ -751,6 +781,95 @@ func highlightCode(code, language string) string {
|
||||||
return strings.TrimRight(buf.String(), "\n")
|
return strings.TrimRight(buf.String(), "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wrapText wraps text to fit within the specified width, accounting for indent
|
||||||
|
func wrapText(text string, width int, indent string) []string {
|
||||||
|
if width <= 0 {
|
||||||
|
return []string{text}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate available width after indent
|
||||||
|
indentWidth := lipgloss.Width(indent)
|
||||||
|
availableWidth := width - indentWidth
|
||||||
|
if availableWidth <= 10 {
|
||||||
|
// If very little space, just return the original text
|
||||||
|
return []string{text}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []string
|
||||||
|
var currentLine strings.Builder
|
||||||
|
currentWidth := 0
|
||||||
|
|
||||||
|
// Split by whitespace while preserving leading/trailing spaces
|
||||||
|
words := strings.Fields(text)
|
||||||
|
if len(words) == 0 {
|
||||||
|
// Preserve empty lines
|
||||||
|
return []string{text}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, word := range words {
|
||||||
|
wordWidth := lipgloss.Width(word)
|
||||||
|
|
||||||
|
// If this is the first word on the line
|
||||||
|
if currentWidth == 0 {
|
||||||
|
// Handle words longer than available width
|
||||||
|
if wordWidth > availableWidth {
|
||||||
|
// Split the word across multiple lines
|
||||||
|
for len(word) > 0 {
|
||||||
|
if availableWidth <= 0 {
|
||||||
|
availableWidth = 10 // Fallback
|
||||||
|
}
|
||||||
|
chunkSize := availableWidth
|
||||||
|
if chunkSize > len(word) {
|
||||||
|
chunkSize = len(word)
|
||||||
|
}
|
||||||
|
result = append(result, word[:chunkSize])
|
||||||
|
word = word[chunkSize:]
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
currentLine.WriteString(word)
|
||||||
|
currentWidth = wordWidth
|
||||||
|
} else {
|
||||||
|
// Check if adding this word (plus a space) would exceed the width
|
||||||
|
spaceAndWordWidth := currentWidth + 1 + wordWidth
|
||||||
|
if spaceAndWordWidth > availableWidth {
|
||||||
|
// Start a new line
|
||||||
|
result = append(result, currentLine.String())
|
||||||
|
currentLine.Reset()
|
||||||
|
|
||||||
|
// Handle words longer than available width
|
||||||
|
if wordWidth > availableWidth {
|
||||||
|
for len(word) > 0 {
|
||||||
|
chunkSize := availableWidth
|
||||||
|
if chunkSize > len(word) {
|
||||||
|
chunkSize = len(word)
|
||||||
|
}
|
||||||
|
result = append(result, word[:chunkSize])
|
||||||
|
word = word[chunkSize:]
|
||||||
|
}
|
||||||
|
currentWidth = 0
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
currentLine.WriteString(word)
|
||||||
|
currentWidth = wordWidth
|
||||||
|
} else {
|
||||||
|
// Add word to current line
|
||||||
|
currentLine.WriteString(" ")
|
||||||
|
currentLine.WriteString(word)
|
||||||
|
currentWidth = spaceAndWordWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is the last word, add the line
|
||||||
|
if i == len(words)-1 && currentLine.Len() > 0 {
|
||||||
|
result = append(result, currentLine.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func (m uiModel) renderItem(item *model.Item, isCursor bool) string {
|
func (m uiModel) renderItem(item *model.Item, isCursor bool) string {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue