mirror of
https://codeberg.org/scip/epuppy.git
synced 2025-12-16 20:11:00 +01:00
add line number support and support for text files
This commit is contained in:
@@ -17,7 +17,17 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
Version string = `v0.0.2`
|
Version string = `v0.0.2`
|
||||||
Usage string = `epuppy [-vd] <epub file>`
|
Usage string = `Usage epuppy [options] <epub file>
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-D --dark enable dark mode
|
||||||
|
-s --store-progress store and use previous (experimental)
|
||||||
|
-n --line-numbers add line numbers
|
||||||
|
-c --config <file> use config <file>
|
||||||
|
-d --debug enable debugging
|
||||||
|
-h --help show help message
|
||||||
|
-v --version show program version
|
||||||
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@@ -25,6 +35,7 @@ type Config struct {
|
|||||||
Debug bool `koanf:"debug"` // -d
|
Debug bool `koanf:"debug"` // -d
|
||||||
StoreProgress bool `koanf:"store-progress"` // -s
|
StoreProgress bool `koanf:"store-progress"` // -s
|
||||||
Darkmode bool `koanf:"dark"` // -D
|
Darkmode bool `koanf:"dark"` // -D
|
||||||
|
LineNumbers bool `koanf:"line-numbers"` // -n
|
||||||
Config string `koanf:"config"` // -c
|
Config string `koanf:"config"` // -c
|
||||||
ColorDark ColorSetting `koanf:"colordark"` // comes from config file only
|
ColorDark ColorSetting `koanf:"colordark"` // comes from config file only
|
||||||
ColorLight ColorSetting `koanf:"colorlight"` // comes from config file only
|
ColorLight ColorSetting `koanf:"colorlight"` // comes from config file only
|
||||||
@@ -52,6 +63,7 @@ func InitConfig(output io.Writer) (*Config, error) {
|
|||||||
flagset.BoolP("debug", "d", false, "enable debugging")
|
flagset.BoolP("debug", "d", false, "enable debugging")
|
||||||
flagset.BoolP("dark", "D", false, "enable dark mode")
|
flagset.BoolP("dark", "D", false, "enable dark mode")
|
||||||
flagset.BoolP("store-progress", "s", false, "store reading progress")
|
flagset.BoolP("store-progress", "s", false, "store reading progress")
|
||||||
|
flagset.BoolP("line-numbers", "n", false, "add line numbers")
|
||||||
flagset.StringP("config", "c", "", "read config from file")
|
flagset.StringP("config", "c", "", "read config from file")
|
||||||
|
|
||||||
if err := flagset.Parse(os.Args[1:]); err != nil {
|
if err := flagset.Parse(os.Args[1:]); err != nil {
|
||||||
|
|||||||
21
cmd/pager.go
21
cmd/pager.go
@@ -189,7 +189,7 @@ func (m Doc) View() string {
|
|||||||
|
|
||||||
// update current line for later saving
|
// update current line for later saving
|
||||||
// FIXME: doesn't work correctly yet
|
// FIXME: doesn't work correctly yet
|
||||||
m.meta.currentline = int(float64(m.meta.lines) * m.viewport.ScrollPercent())
|
m.meta.currentline = int(float64(m.viewport.TotalLineCount()) * m.viewport.ScrollPercent())
|
||||||
|
|
||||||
var helpView string
|
var helpView string
|
||||||
if m.help.ShowAll {
|
if m.help.ShowAll {
|
||||||
@@ -234,13 +234,28 @@ func Pager(conf *Config, title, message string) (int, error) {
|
|||||||
scrollto = conf.InitialProgress
|
scrollto = conf.InitialProgress
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if conf.LineNumbers {
|
||||||
|
catn := ""
|
||||||
|
for idx, line := range strings.Split(message, "\n") {
|
||||||
|
catn += fmt.Sprintf("%d: %s\n", idx, line)
|
||||||
|
}
|
||||||
|
message = catn
|
||||||
|
}
|
||||||
|
|
||||||
meta := Meta{
|
meta := Meta{
|
||||||
initialprogress: scrollto,
|
initialprogress: scrollto,
|
||||||
lines: len(strings.Split(message, "\r\n")),
|
lines: len(strings.Split(message, "\n")),
|
||||||
}
|
}
|
||||||
|
|
||||||
p := tea.NewProgram(
|
p := tea.NewProgram(
|
||||||
Doc{content: message, title: title, initialwidth: width, meta: &meta, config: conf, keys: keys},
|
Doc{
|
||||||
|
content: message,
|
||||||
|
title: title,
|
||||||
|
initialwidth: width,
|
||||||
|
meta: &meta,
|
||||||
|
config: conf,
|
||||||
|
keys: keys,
|
||||||
|
},
|
||||||
tea.WithAltScreen(), // use the full size of the terminal in its "alternate screen buffer"
|
tea.WithAltScreen(), // use the full size of the terminal in its "alternate screen buffer"
|
||||||
tea.WithMouseCellMotion(), // turn on mouse support so we can track the mouse wheel
|
tea.WithMouseCellMotion(), // turn on mouse support so we can track the mouse wheel
|
||||||
)
|
)
|
||||||
|
|||||||
27
cmd/view.go
27
cmd/view.go
@@ -2,12 +2,32 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tlinden/epuppy/pkg/epub"
|
"github.com/tlinden/epuppy/pkg/epub"
|
||||||
)
|
)
|
||||||
|
|
||||||
func View(conf *Config) (int, error) {
|
func View(conf *Config) (int, error) {
|
||||||
|
switch filepath.Ext(conf.Document) {
|
||||||
|
case ".epub":
|
||||||
|
return ViewEpub(conf)
|
||||||
|
default:
|
||||||
|
return ViewText(conf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ViewText(conf *Config) (int, error) {
|
||||||
|
data, err := os.ReadFile(conf.Document)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return Pager(conf, conf.Document, string(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ViewEpub(conf *Config) (int, error) {
|
||||||
book, err := epub.Open(conf.Document)
|
book, err := epub.Open(conf.Document)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
@@ -35,8 +55,11 @@ func View(conf *Config) (int, error) {
|
|||||||
|
|
||||||
for _, content := range book.Content {
|
for _, content := range book.Content {
|
||||||
if len(content.Body) > 0 {
|
if len(content.Body) > 0 {
|
||||||
buf.WriteString(conf.Colors.Chapter.
|
if content.Title != "" {
|
||||||
Render(fmt.Sprintf("Chapter %d: %s", chapter, content.Title)))
|
buf.WriteString(conf.Colors.Chapter.
|
||||||
|
Render(fmt.Sprintf("──────┤ %s ├──────", content.Title)))
|
||||||
|
|
||||||
|
}
|
||||||
buf.WriteString("\r\n\r\n")
|
buf.WriteString("\r\n\r\n")
|
||||||
buf.WriteString(conf.Colors.Body.Render(content.Body))
|
buf.WriteString(conf.Colors.Body.Render(content.Body))
|
||||||
buf.WriteString("\r\n\r\n\r\n\r\n")
|
buf.WriteString("\r\n\r\n\r\n\r\n")
|
||||||
|
|||||||
@@ -3,9 +3,19 @@ package epub
|
|||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
cleantitle = regexp.MustCompile(`(?s)<head>.*</head>`)
|
||||||
|
cleanmarkup = regexp.MustCompile(`<[^<>]+>`)
|
||||||
|
cleanentities = regexp.MustCompile(`&.+;`)
|
||||||
|
cleancomments = regexp.MustCompile(`/*.*/`)
|
||||||
|
cleanspace = regexp.MustCompile(`^\s*`)
|
||||||
|
cleanh1 = regexp.MustCompile(`<h[1-6].*</h[1-6]>`)
|
||||||
|
)
|
||||||
|
|
||||||
// Content nav-point content
|
// Content nav-point content
|
||||||
type Content struct {
|
type Content struct {
|
||||||
Src string `xml:"src,attr" json:"src"`
|
Src string `xml:"src,attr" json:"src"`
|
||||||
|
|||||||
@@ -1,18 +1,5 @@
|
|||||||
package epub
|
package epub
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
cleantitle = regexp.MustCompile(`(?s)<head>.*</head>`)
|
|
||||||
cleanmarkup = regexp.MustCompile(`<[^<>]+>`)
|
|
||||||
cleanentities = regexp.MustCompile(`&.+;`)
|
|
||||||
cleancomments = regexp.MustCompile(`/*.*/`)
|
|
||||||
cleanspace = regexp.MustCompile(`^\s*`)
|
|
||||||
cleanh1 = regexp.MustCompile(`<h[1-6].*</h[1-6]>`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Ncx OPS/toc.ncx
|
// Ncx OPS/toc.ncx
|
||||||
type Ncx struct {
|
type Ncx struct {
|
||||||
Points []*NavPoint `xml:"navMap>navPoint" json:"points"`
|
Points []*NavPoint `xml:"navMap>navPoint" json:"points"`
|
||||||
|
|||||||
Reference in New Issue
Block a user