|
|
@ -4,6 +4,7 @@ package main |
|
|
|
import ( |
|
|
|
"flag" |
|
|
|
"fmt" |
|
|
|
"log" |
|
|
|
"os" |
|
|
|
"path/filepath" |
|
|
|
"strings" |
|
|
@ -15,6 +16,7 @@ import ( |
|
|
|
"github.com/charmbracelet/lipgloss" |
|
|
|
pdf "github.com/johbar/go-poppler" |
|
|
|
"github.com/sahilm/fuzzy" |
|
|
|
"golang.org/x/term" |
|
|
|
) |
|
|
|
|
|
|
|
// filenameFilterMode searches by PDF file name.
|
|
|
@ -67,17 +69,17 @@ func readPDF(name string) (string, error) { |
|
|
|
|
|
|
|
// model offers the core of the state for the entire UI.
|
|
|
|
type model struct { |
|
|
|
input textinput.Model // Fuzzy search interface
|
|
|
|
|
|
|
|
datasheets []datasheet // All datasheets under cwd
|
|
|
|
datasheetNames []string // All datasheet names (caching)
|
|
|
|
filteredDatasheets []string // Filtered view on all datasheets
|
|
|
|
loadDatasheetSpinner spinner.Model // Spinner to show while loading datasheets
|
|
|
|
datasheetsLoaded bool // Whether or not the datasheets are loaded or not
|
|
|
|
|
|
|
|
datasheetViewport viewport.Model // Viewport for the PDF content
|
|
|
|
|
|
|
|
filterMode string // The filtering mode ("filename", "content")
|
|
|
|
input textinput.Model // Fuzzy search interface
|
|
|
|
filterMode string // The filtering mode ("filename", "content")
|
|
|
|
|
|
|
|
datasheets []datasheet // All datasheets under cwd
|
|
|
|
datasheetNames []string // All datasheet names (caching)
|
|
|
|
datasheetsStyle lipgloss.Style // Style to use for listing datasheets
|
|
|
|
filteredDatasheets []string // Filtered view on all datasheets
|
|
|
|
loadDatasheetSpinner spinner.Model // Spinner to show while loading datasheets
|
|
|
|
datasheetsLoaded bool // Whether or not the datasheets are loaded or not
|
|
|
|
datasheetViewport viewport.Model // Viewport for the PDF content
|
|
|
|
datasheetViewportStyle lipgloss.Style // Style to show while showing datasheet viewport
|
|
|
|
} |
|
|
|
|
|
|
|
// datasheetFromName retrieves a datasheet via a name.
|
|
|
@ -107,25 +109,38 @@ type datasheet struct { |
|
|
|
} |
|
|
|
|
|
|
|
// initialModel constucts an initial state for the UI.
|
|
|
|
func initialModel() model { |
|
|
|
func initialModel(width int, height int) model { |
|
|
|
input := textinput.New() |
|
|
|
input.Focus() |
|
|
|
|
|
|
|
// TODO: set width/heigh to match terminal. this should also
|
|
|
|
// be set in relation to the list of filenames also. they
|
|
|
|
// should have some visually pleasing ratio set i imagine
|
|
|
|
viewp := viewport.New(60, 30) |
|
|
|
datasheetViewport := viewport.New(width/2+20, height/2) |
|
|
|
datasheetViewportStyle := lipgloss.NewStyle(). |
|
|
|
BorderStyle(lipgloss.NormalBorder()). |
|
|
|
BorderForeground(lipgloss.Color("63")). |
|
|
|
Padding(2) |
|
|
|
|
|
|
|
loadDatasheetSpinner := spinner.New() |
|
|
|
loadDatasheetSpinner.Spinner = spinner.Dot |
|
|
|
loadDatasheetSpinner.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("205")) |
|
|
|
loadDatasheetSpinner.Style = lipgloss.NewStyle(). |
|
|
|
Foreground(lipgloss.Color("205")) |
|
|
|
|
|
|
|
datasheetsStyle := lipgloss.NewStyle(). |
|
|
|
Width(width/2 - 30). |
|
|
|
Height(height/2 - 30). |
|
|
|
MarginRight(2). |
|
|
|
BorderStyle(lipgloss.NormalBorder()). |
|
|
|
BorderForeground(lipgloss.Color("63")). |
|
|
|
Padding(2) |
|
|
|
|
|
|
|
m := model{ |
|
|
|
input: input, |
|
|
|
datasheetsLoaded: false, |
|
|
|
loadDatasheetSpinner: loadDatasheetSpinner, |
|
|
|
datasheetViewport: viewp, |
|
|
|
filterMode: filenameFilterMode, |
|
|
|
input: input, |
|
|
|
filterMode: filenameFilterMode, |
|
|
|
|
|
|
|
datasheetsLoaded: false, |
|
|
|
loadDatasheetSpinner: loadDatasheetSpinner, |
|
|
|
datasheetViewport: datasheetViewport, |
|
|
|
datasheetViewportStyle: datasheetViewportStyle, |
|
|
|
datasheetsStyle: datasheetsStyle, |
|
|
|
} |
|
|
|
|
|
|
|
return m |
|
|
@ -235,7 +250,6 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { |
|
|
|
m.datasheetViewport.SetContent(viewportText) |
|
|
|
} |
|
|
|
|
|
|
|
// TODO: handle terminal resizing
|
|
|
|
switch msg := msg.(type) { |
|
|
|
case loadedDatasheetsMsg: |
|
|
|
m.datasheets = msg.datasheets |
|
|
@ -246,6 +260,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { |
|
|
|
m.datasheetViewport.SetContent(selectedDatasheet) |
|
|
|
|
|
|
|
m.datasheetsLoaded = true |
|
|
|
case tea.WindowSizeMsg: |
|
|
|
// TODO: handle terminal resizing
|
|
|
|
// resize listing / viewport
|
|
|
|
case tea.KeyMsg: |
|
|
|
switch msg.String() { |
|
|
|
case "ctrl+c": |
|
|
@ -271,7 +288,11 @@ func (m model) View() string { |
|
|
|
} |
|
|
|
|
|
|
|
// TODO: style further with lipgloss, e.g. borders, margins, etc.
|
|
|
|
panes := lipgloss.JoinHorizontal(lipgloss.Left, sheets, m.datasheetViewport.View()) |
|
|
|
panes := lipgloss.JoinHorizontal( |
|
|
|
lipgloss.Left, |
|
|
|
m.datasheetsStyle.Render(sheets), |
|
|
|
m.datasheetViewportStyle.Render(m.datasheetViewport.View()), |
|
|
|
) |
|
|
|
|
|
|
|
body.WriteString(panes) |
|
|
|
|
|
|
@ -303,13 +324,17 @@ func main() { |
|
|
|
|
|
|
|
f, err := tea.LogToFile("debug.log", "debug") |
|
|
|
if err != nil { |
|
|
|
fmt.Println("fatal:", err) |
|
|
|
os.Exit(1) |
|
|
|
log.Fatal(err) |
|
|
|
} |
|
|
|
defer f.Close() |
|
|
|
|
|
|
|
width, height, err := term.GetSize(0) |
|
|
|
if err != nil { |
|
|
|
log.Fatal(err) |
|
|
|
} |
|
|
|
|
|
|
|
p := tea.NewProgram( |
|
|
|
initialModel(), |
|
|
|
initialModel(width, height), |
|
|
|
tea.WithAltScreen(), |
|
|
|
tea.WithMouseCellMotion(), |
|
|
|
) |
|
|
|