mirror of
https://github.com/walles/moar.git
synced 2024-09-17 15:07:11 +03:00
Switch highlighting engine to Chroma
Which is linked into here, so no need for users to install any external tools. Chroma home page: https://github.com/alecthomas/chroma
This commit is contained in:
parent
570d780bc2
commit
54935615ed
@ -8,9 +8,5 @@ language: go
|
||||
go:
|
||||
- 1.13.x
|
||||
|
||||
before_install:
|
||||
# Needed for test suite to pass
|
||||
- sudo apt-get install -y highlight
|
||||
|
||||
script:
|
||||
- ./test.sh
|
||||
|
14
README.md
14
README.md
@ -10,9 +10,8 @@ doesn't work that way,
|
||||
|
||||
Doing the right thing includes:
|
||||
|
||||
* **Syntax highlight** source code by default if
|
||||
[Highlight](http://www.andre-simon.de/doku/highlight/en/highlight.php)
|
||||
is installed.
|
||||
* **Syntax highlight** source code by default using
|
||||
[Chroma](https://github.com/alecthomas/chroma)
|
||||
* **Search is incremental** / find-as-you-type just like in
|
||||
[Chrome](http://www.google.com/chrome) or
|
||||
[Emacs](http://www.gnu.org/software/emacs/)
|
||||
@ -106,14 +105,7 @@ The `m.Page()` parameter can also be initialized using `NewReaderFromText()` or
|
||||
Developing
|
||||
----------
|
||||
|
||||
First, install [Highlight](http://www.andre-simon.de/zip/download.php),
|
||||
otherwise the test suite won't pass:
|
||||
|
||||
* On macOS: [`brew install highlight`](https://brew.sh/)
|
||||
* On Ubuntu: [`sudo apt-get install highlight`](https://packages.ubuntu.com/search?suite=all&searchon=names&keywords=highlight)
|
||||
* Elsewhere, follow [instructions](http://www.andre-simon.de/zip/download.php)
|
||||
|
||||
Also, you need the [go tools](https://golang.org/doc/install).
|
||||
You need the [go tools](https://golang.org/doc/install).
|
||||
|
||||
Run tests:
|
||||
|
||||
|
2
go.mod
2
go.mod
@ -3,9 +3,9 @@ module github.com/walles/moar
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/alecthomas/chroma v0.8.2
|
||||
github.com/gdamore/tcell/v2 v2.0.0
|
||||
github.com/google/go-cmp v0.3.0 // indirect
|
||||
github.com/pkg/errors v0.8.1 // indirect
|
||||
github.com/sirupsen/logrus v1.4.2
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5
|
||||
gotest.tools v2.2.0+incompatible
|
||||
|
22
go.sum
22
go.sum
@ -1,5 +1,16 @@
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
|
||||
github.com/alecthomas/chroma v0.8.2 h1:x3zkuE2lUk/RIekyAJ3XRqSCP4zwWDfcw/YJCuCAACg=
|
||||
github.com/alecthomas/chroma v0.8.2/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM=
|
||||
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
|
||||
github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
|
||||
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
|
||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
|
||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
|
||||
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||
github.com/gdamore/tcell/v2 v2.0.0 h1:GRWG8aLfWAlekj9Q6W29bVvkHENc6hp79XOqG4AWDOs=
|
||||
@ -13,19 +24,26 @@ github.com/lucasb-eyer/go-colorful v1.0.2 h1:mCMFu6PgSozg9tDNMMK3g18oJBX7oYGrC09
|
||||
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@ -41,6 +59,10 @@ golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756 h1:9nuHUbU8dRnRRfj9KjWUVrJeo
|
||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY=
|
||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418 h1:HlFl4V6pEMziuLXyRkm5BIYq1y1GAbb02pRlWvI54OM=
|
||||
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8=
|
||||
|
@ -156,8 +156,6 @@ func TestTabHandling(t *testing.T) {
|
||||
assertIndexOfFirstX(t, "\x09Johan\x09x", 12)
|
||||
}
|
||||
|
||||
// This test assumes highlight is installed:
|
||||
// http://www.andre-simon.de/zip/download.php
|
||||
func TestCodeHighlighting(t *testing.T) {
|
||||
// From: https://coderwall.com/p/_fmbug/go-get-path-to-current-file
|
||||
_, filename, _, ok := runtime.Caller(0)
|
||||
|
100
m/reader.go
100
m/reader.go
@ -5,17 +5,21 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/alecthomas/chroma"
|
||||
"github.com/alecthomas/chroma/formatters"
|
||||
"github.com/alecthomas/chroma/lexers"
|
||||
"github.com/alecthomas/chroma/styles"
|
||||
)
|
||||
|
||||
// Reader reads a file into an array of strings.
|
||||
@ -247,54 +251,6 @@ func newReaderFromCommand(filename string, filterCommand ...string) (*Reader, er
|
||||
return reader, nil
|
||||
}
|
||||
|
||||
func canHighlight(filename string) bool {
|
||||
extension := filepath.Ext(filename)
|
||||
if len(extension) <= 1 {
|
||||
// No extension or a single "."
|
||||
return false
|
||||
}
|
||||
|
||||
if extension == ".txt" {
|
||||
// Highlighting text files won't be of much use.
|
||||
//
|
||||
// Also: https://github.com/walles/moar/issues/29
|
||||
return false
|
||||
}
|
||||
|
||||
// Remove leading dot from the extension
|
||||
extension = extension[1:]
|
||||
|
||||
// Check file extension vs "highlight --list-scripts=langs" before calling
|
||||
// highlight, otherwise files with unsupported extensions (like .log) get
|
||||
// messed upp.
|
||||
highlight := exec.Command("highlight", "--list-scripts=langs")
|
||||
outBytes, err := highlight.CombinedOutput()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
extensionMatcher := regexp.MustCompile("[^() ]+")
|
||||
|
||||
outString := string(outBytes)
|
||||
outLines := strings.Split(outString, "\n")
|
||||
for _, line := range outLines {
|
||||
parts := strings.Split(line, ": ")
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Pick out all extensions from this line
|
||||
for _, supportedExtension := range extensionMatcher.FindAllString(parts[1], -1) {
|
||||
if extension == supportedExtension {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No match
|
||||
return false
|
||||
}
|
||||
|
||||
func tryOpen(filename string) error {
|
||||
// Try opening the file
|
||||
tryMe, err := os.Open(filename)
|
||||
@ -307,7 +263,10 @@ func tryOpen(filename string) error {
|
||||
buffer := make([]byte, 1)
|
||||
_, err = tryMe.Read(buffer)
|
||||
|
||||
if err != nil && err.Error() == "EOF" {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if err.Error() == "EOF" {
|
||||
// Empty file, this is fine
|
||||
return nil
|
||||
}
|
||||
@ -318,8 +277,8 @@ func tryOpen(filename string) error {
|
||||
// NewReaderFromFilename creates a new file reader.
|
||||
//
|
||||
// The Reader will try to uncompress various compressed file format, and also
|
||||
// apply highlighting to the file using highlight:
|
||||
// http://www.andre-simon.de/doku/highlight/en/highlight.php
|
||||
// apply highlighting to the file using Chroma:
|
||||
// https://github.com/alecthomas/chroma
|
||||
func NewReaderFromFilename(filename string) (*Reader, error) {
|
||||
fileError := tryOpen(filename)
|
||||
if fileError != nil {
|
||||
@ -336,21 +295,38 @@ func NewReaderFromFilename(filename string) (*Reader, error) {
|
||||
return newReaderFromCommand(filename, "xz", "-d", "-c")
|
||||
}
|
||||
|
||||
// Highlight input file using highlight:
|
||||
// http://www.andre-simon.de/doku/highlight/en/highlight.php
|
||||
if canHighlight(filename) {
|
||||
highlighted, err := newReaderFromCommand(filename, "highlight", "--out-format=esc", "-i")
|
||||
if err == nil {
|
||||
return highlighted, err
|
||||
}
|
||||
// Highlight input file using Chroma:
|
||||
// https://github.com/alecthomas/chroma
|
||||
lexer := lexers.Match(filename)
|
||||
if lexer == nil {
|
||||
lexer = lexers.Fallback
|
||||
}
|
||||
|
||||
stream, err := os.Open(filename)
|
||||
// See: https://github.com/alecthomas/chroma#identifying-the-language
|
||||
// FIXME: Do we actually need this? We should profile our reader performance
|
||||
// with and without.
|
||||
lexer = chroma.Coalesce(lexer)
|
||||
|
||||
formatter := formatters.Get("terminal16m")
|
||||
if formatter == nil {
|
||||
formatter = formatters.Fallback
|
||||
}
|
||||
|
||||
contents, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reader := NewReaderFromStream(filename, stream)
|
||||
iterator, err := lexer.Tokenise(nil, string(contents))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var stringBuffer bytes.Buffer
|
||||
err = formatter.Format(&stringBuffer, styles.Native, iterator)
|
||||
|
||||
// FIXME: Do basename(filename) first?
|
||||
reader := NewReaderFromText(filename, stringBuffer.String())
|
||||
return reader, nil
|
||||
}
|
||||
|
||||
|
9
moar.go
9
moar.go
@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
@ -32,14 +31,6 @@ func printUsage(output io.Writer) {
|
||||
|
||||
flag.PrintDefaults()
|
||||
|
||||
_, err := exec.LookPath("highlight")
|
||||
if err != nil {
|
||||
// Highlight not installed
|
||||
fmt.Fprintln(output)
|
||||
fmt.Fprintln(output, "To enable syntax highlighting when viewing source code, install")
|
||||
fmt.Fprintln(output, "Highlight (http://www.andre-simon.de/zip/download.php).")
|
||||
}
|
||||
|
||||
moarPath, err := filepath.Abs(os.Args[0])
|
||||
if err == nil {
|
||||
pagerValue, err := filepath.Abs(os.Getenv("PAGER"))
|
||||
|
Loading…
Reference in New Issue
Block a user