Auto detect line ending on startup
This commit is contained in:
parent
2cc48cfbb0
commit
e4cc33f098
8 changed files with 168 additions and 40 deletions
|
@ -18,8 +18,8 @@
|
|||
<div class="reveal">
|
||||
<div class="slides">
|
||||
<section data-markdown="/content.md"
|
||||
data-separator="^{{ .Reveal.LineEnding -}}{{ .Reveal.HorizontalSeparator }}{{- .Reveal.LineEnding }}"
|
||||
data-separator-vertical="^{{ .Reveal.LineEnding -}}{{ .Reveal.VerticalSeparator }}{{- .Reveal.LineEnding }}"
|
||||
data-separator="^{{ .Reveal.LineEnding.Escaped -}}{{ .Reveal.HorizontalSeparator }}{{- .Reveal.LineEnding.Escaped }}"
|
||||
data-separator-vertical="^{{ .Reveal.LineEnding.Escaped -}}{{ .Reveal.VerticalSeparator }}{{- .Reveal.LineEnding.Escaped }}"
|
||||
data-separator-notes="^Note:"
|
||||
data-charset="iso-8859-15">
|
||||
</section>
|
||||
|
|
2
go.sum
2
go.sum
|
@ -49,8 +49,6 @@ github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJ
|
|||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/Masterminds/sprig/v3 v3.2.1 h1:n6EPaDyLSvCEa3frruQvAiHuNp2dhBlMSmkEr+HuzGc=
|
||||
github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
|
||||
github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8=
|
||||
github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package rendering
|
||||
|
||||
const (
|
||||
LineEnding string = "\\n"
|
||||
)
|
|
@ -1,5 +0,0 @@
|
|||
package rendering
|
||||
|
||||
const (
|
||||
LineEnding string = "\\r\\n"
|
||||
)
|
|
@ -21,6 +21,8 @@ import (
|
|||
"github.com/bmatcuk/doublestar/v2"
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/baez90/goveal/internal/encoding"
|
||||
)
|
||||
|
||||
var defaultParams = RevealParams{
|
||||
|
@ -32,24 +34,23 @@ var defaultParams = RevealParams{
|
|||
VerticalSeparator: "---",
|
||||
SlideNumberVisibility: "all",
|
||||
SlideNumberFormat: "h.v",
|
||||
LineEnding: LineEnding,
|
||||
StyleSheets: make([]string, 0),
|
||||
FilesToMonitor: make([]string, 0),
|
||||
}
|
||||
|
||||
type RevealParams struct {
|
||||
Theme string `mapstructure:"theme"`
|
||||
CodeTheme string `mapstructure:"codeTheme"`
|
||||
Transition string `mapstructure:"transition"`
|
||||
NavigationMode string `mapstructure:"navigationMode"`
|
||||
HorizontalSeparator string `mapstructure:"horizontalSeparator"`
|
||||
VerticalSeparator string `mapstructure:"verticalSeparator"`
|
||||
SlideNumberVisibility string `mapstructure:"slideNumberVisibility"`
|
||||
SlideNumberFormat string `mapstructure:"slideNumberFormat"`
|
||||
StyleSheets []string `mapstructure:"stylesheets"`
|
||||
FilesToMonitor []string `mapstructure:"filesToMonitor"`
|
||||
WorkingDirectory string `mapstructure:"working-dir"`
|
||||
LineEnding string `mapstructure:"-"`
|
||||
Theme string `mapstructure:"theme"`
|
||||
CodeTheme string `mapstructure:"codeTheme"`
|
||||
Transition string `mapstructure:"transition"`
|
||||
NavigationMode string `mapstructure:"navigationMode"`
|
||||
HorizontalSeparator string `mapstructure:"horizontalSeparator"`
|
||||
VerticalSeparator string `mapstructure:"verticalSeparator"`
|
||||
SlideNumberVisibility string `mapstructure:"slideNumberVisibility"`
|
||||
SlideNumberFormat string `mapstructure:"slideNumberFormat"`
|
||||
StyleSheets []string `mapstructure:"stylesheets"`
|
||||
FilesToMonitor []string `mapstructure:"filesToMonitor"`
|
||||
WorkingDirectory string `mapstructure:"working-dir"`
|
||||
LineEnding encoding.LineEnding `mapstructure:"-"`
|
||||
}
|
||||
|
||||
func (params *RevealParams) Load() error {
|
||||
|
|
|
@ -5,27 +5,31 @@ import (
|
|||
"io/fs"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/baez90/goveal/assets"
|
||||
"github.com/baez90/goveal/internal/app/rendering"
|
||||
"github.com/baez90/goveal/internal/app/routing"
|
||||
"github.com/baez90/goveal/internal/encoding"
|
||||
)
|
||||
|
||||
const (
|
||||
markdownFilePath = "/content.md"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Host string
|
||||
Port uint16
|
||||
MarkdownPath string
|
||||
RevealParams *rendering.RevealParams
|
||||
}
|
||||
type (
|
||||
Config struct {
|
||||
Host string
|
||||
Port uint16
|
||||
MarkdownPath string
|
||||
RevealParams *rendering.RevealParams
|
||||
}
|
||||
|
||||
type HTTPServer struct {
|
||||
listener net.Listener
|
||||
handler http.Handler
|
||||
}
|
||||
HTTPServer struct {
|
||||
listener net.Listener
|
||||
handler http.Handler
|
||||
}
|
||||
)
|
||||
|
||||
func (srv HTTPServer) Serve() error {
|
||||
return http.Serve(srv.listener, srv.handler)
|
||||
|
@ -37,6 +41,9 @@ func (srv HTTPServer) ListenAddress() string {
|
|||
|
||||
func NewHTTPServer(config Config) (srv *HTTPServer, err error) {
|
||||
noCacheFiles := append(config.RevealParams.FilesToMonitor, markdownFilePath)
|
||||
if err := detectMarkdownFileEnding(config.MarkdownPath, config.RevealParams); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
router := &routing.RegexpRouter{}
|
||||
var tmplRenderer rendering.RevealRenderer
|
||||
|
@ -92,3 +99,20 @@ func NewHTTPServer(config Config) (srv *HTTPServer, err error) {
|
|||
|
||||
return
|
||||
}
|
||||
|
||||
func detectMarkdownFileEnding(filePath string, params *rendering.RevealParams) error {
|
||||
f, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = f.Close()
|
||||
}()
|
||||
|
||||
if le, err := encoding.Detect(f); err != nil {
|
||||
return err
|
||||
} else {
|
||||
params.LineEnding = le
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
44
internal/encoding/line_ending.go
Normal file
44
internal/encoding/line_ending.go
Normal file
|
@ -0,0 +1,44 @@
|
|||
package encoding
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
LineEndingUnknown LineEnding = ""
|
||||
LineEndingWindows LineEnding = "\r\n"
|
||||
LineEndingUnix LineEnding = "\n"
|
||||
)
|
||||
|
||||
type LineEnding string
|
||||
|
||||
func (e LineEnding) String() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
func (e LineEnding) Escaped() string {
|
||||
switch e {
|
||||
case LineEndingUnix:
|
||||
return "\\n"
|
||||
case LineEndingWindows:
|
||||
return "\\r\\n"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func Detect(reader io.Reader) (LineEnding, error) {
|
||||
bufferedReader := bufio.NewReader(reader)
|
||||
line, err := bufferedReader.ReadString(byte('\n'))
|
||||
if err != nil {
|
||||
return LineEndingUnknown, err
|
||||
}
|
||||
|
||||
lineLength := len(line)
|
||||
if lineLength <= 1 || line[lineLength-2:] != LineEndingWindows.String() {
|
||||
return LineEndingUnix, nil
|
||||
}
|
||||
|
||||
return LineEndingWindows, nil
|
||||
}
|
74
internal/encoding/line_ending_test.go
Normal file
74
internal/encoding/line_ending_test.go
Normal file
|
@ -0,0 +1,74 @@
|
|||
package encoding_test
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/baez90/goveal/internal/encoding"
|
||||
)
|
||||
|
||||
func TestDetect(t *testing.T) {
|
||||
type args struct {
|
||||
reader io.Reader
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want encoding.LineEnding
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Empty file expect unknown",
|
||||
args: args{
|
||||
reader: strings.NewReader(""),
|
||||
},
|
||||
want: encoding.LineEndingUnknown,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "File with only Unix line ending",
|
||||
args: args{
|
||||
reader: strings.NewReader("\n"),
|
||||
},
|
||||
want: encoding.LineEndingUnix,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "File with only Windows line ending",
|
||||
args: args{
|
||||
reader: strings.NewReader("\r\n"),
|
||||
},
|
||||
want: encoding.LineEndingWindows,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "File with multiple lines - Unix file ending",
|
||||
args: args{
|
||||
reader: strings.NewReader("Hello, World\nThis comes from Unix!\n"),
|
||||
},
|
||||
want: encoding.LineEndingUnix,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "File with multiple lines - Windows file ending",
|
||||
args: args{
|
||||
reader: strings.NewReader("Hello, World\r\nThis comes from Windows!\r\n"),
|
||||
},
|
||||
want: encoding.LineEndingWindows,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := encoding.Detect(tt.args.reader)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Detect() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("Detect() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue