1
1
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:
Johan Walles 2021-01-09 17:18:10 +01:00
parent 570d780bc2
commit 54935615ed
7 changed files with 64 additions and 89 deletions

View File

@ -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

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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)

View File

@ -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
}

View File

@ -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"))