mirror of
https://github.com/walles/moar.git
synced 2024-11-26 04:21:11 +03:00
Merge remote-tracking branch 'origin/master' into johan/ui-colors-from-chroma
This commit is contained in:
commit
a99c17012b
8
MOUSE.md
8
MOUSE.md
@ -5,8 +5,8 @@
|
||||
- `scroll` makes `moar` process mouse events from your terminal, thus enabling mouse scrolling work,
|
||||
but disabling the ability to select text with mouse in the usual way. Selecting text will require using your terminal's capability to bypass mouse protocol.
|
||||
Most terminals support this capability, see [Selection workarounds for `scroll` mode](#mouse-selection-workarounds-for-scroll-mode) for details.
|
||||
- `mark` makes `moar` not process mouse events. This makes selecting and copying text work, but scrolling might not be possible, depending on your terminal and its configuration.
|
||||
- `auto` uses `mark` on terminals where we know it won't break scrolling, and
|
||||
- `select` makes `moar` not process mouse events. This makes selecting and copying text work, but scrolling might not be possible, depending on your terminal and its configuration.
|
||||
- `auto` uses `select` on terminals where we know it won't break scrolling, and
|
||||
`scroll` on all others. [The white list lives in the
|
||||
`mouseTrackingRecommended()` function in
|
||||
`screen.go`](https://github.com/walles/moar/blob/master/twin/screen.go).
|
||||
@ -15,9 +15,9 @@ The reason these tradeoffs exist is that if `moar` requests mouse events from th
|
||||
it should process _all_ mouse events, including attempts to select text. This is the case with every console application.
|
||||
|
||||
However, some terminals can send "fake" arrow key presses to applications which _do not_ request processing mouse events.
|
||||
This means that on those terminals, you will be better off using `--mousemode mark` option, given that you also have this feature enabled (it's usually on by default).
|
||||
This means that on those terminals, you will be better off using `--mousemode select` option, given that you also have this feature enabled (it's usually on by default).
|
||||
With this setup, both scrolling and text selecting in the usual way will work.
|
||||
To check whether this could work, simply run `moar` with option `--mousemode mark` and see if scrolling still works.
|
||||
To check whether this could work, simply run `moar` with option `--mousemode select` and see if scrolling still works.
|
||||
|
||||
## Mouse Selection Workarounds for `scroll` Mode
|
||||
|
||||
|
6
go.mod
6
go.mod
@ -5,11 +5,13 @@ go 1.20
|
||||
require (
|
||||
github.com/alecthomas/chroma/v2 v2.12.0
|
||||
github.com/google/go-cmp v0.5.9
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
golang.org/x/sys v0.1.0
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56
|
||||
gotest.tools/v3 v3.3.0
|
||||
)
|
||||
|
||||
require github.com/dlclark/regexp2 v1.10.0 // indirect
|
||||
require (
|
||||
github.com/dlclark/regexp2 v1.10.0 // indirect
|
||||
github.com/stretchr/testify v1.7.0 // indirect
|
||||
)
|
||||
|
10
go.sum
10
go.sum
@ -2,6 +2,7 @@ github.com/alecthomas/assert/v2 v2.2.1 h1:XivOgYcduV98QCahG8T5XTezV5bylXe+lBxLG2
|
||||
github.com/alecthomas/chroma/v2 v2.12.0 h1:Wh8qLEgMMsN7mgyG8/qIpegky2Hvzr4By6gEF7cmWgw=
|
||||
github.com/alecthomas/chroma/v2 v2.12.0/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurGF0EpseFXdKMBw=
|
||||
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
|
||||
@ -10,15 +11,15 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@ -47,5 +48,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=
|
||||
gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A=
|
||||
|
6
moar.1
6
moar.1
@ -45,9 +45,9 @@ Print debug logs after exiting, less verbose than
|
||||
Scrolls automatically to follow piped input, just like
|
||||
.B tail \-f
|
||||
.TP
|
||||
\fB\-\-mousemode\fR={\fBauto\fR | \fBmark\fR | \fBscroll\fR}
|
||||
Guarantee marking text with the mouse works but maybe not mouse scrolling.
|
||||
Or guarantee mouse scrolling works but marking requiring extra effort.
|
||||
\fB\-\-mousemode\fR={\fBauto\fR | \fBselect\fR | \fBscroll\fR}
|
||||
Guarantee selecting text with the mouse works but maybe not mouse scrolling.
|
||||
Or guarantee mouse scrolling works but selecting text requiring extra effort.
|
||||
Details here: https://github.com/walles/moar/blob/master/MOUSE.md
|
||||
.TP
|
||||
\fB\-\-no\-clear\-on\-exit\fR
|
||||
|
8
moar.go
8
moar.go
@ -245,13 +245,13 @@ func parseMouseMode(mouseMode string) (twin.MouseMode, error) {
|
||||
switch mouseMode {
|
||||
case "auto":
|
||||
return twin.MouseModeAuto, nil
|
||||
case "mark":
|
||||
return twin.MouseModeMark, nil
|
||||
case "select", "mark":
|
||||
return twin.MouseModeSelect, nil
|
||||
case "scroll":
|
||||
return twin.MouseModeScroll, nil
|
||||
}
|
||||
|
||||
return twin.MouseModeAuto, fmt.Errorf("Valid modes are auto, mark and scroll")
|
||||
return twin.MouseModeAuto, fmt.Errorf("Valid modes are auto, select and scroll")
|
||||
}
|
||||
|
||||
func pumpToStdout(inputFilename *string) error {
|
||||
@ -408,7 +408,7 @@ func main() {
|
||||
flagSet,
|
||||
"mousemode",
|
||||
twin.MouseModeAuto,
|
||||
"Mouse mode: auto, mark or scroll: https://github.com/walles/moar/blob/master/MOUSE.md",
|
||||
"Mouse mode: auto, select or scroll: https://github.com/walles/moar/blob/master/MOUSE.md",
|
||||
parseMouseMode,
|
||||
)
|
||||
|
||||
|
@ -5,7 +5,6 @@ import (
|
||||
"math"
|
||||
|
||||
"github.com/alecthomas/chroma/v2"
|
||||
"github.com/lucasb-eyer/go-colorful"
|
||||
)
|
||||
|
||||
// Create using NewColor16(), NewColor256 or NewColor24Bit(), or use
|
||||
@ -164,6 +163,19 @@ func (color Color) String() string {
|
||||
panic(fmt.Errorf("unhandled color type %d", color.ColorType()))
|
||||
}
|
||||
|
||||
func (color Color) to24Bit() Color {
|
||||
if color.ColorType() == ColorType24bit {
|
||||
return color
|
||||
}
|
||||
|
||||
if color.ColorType() == ColorType8 || color.ColorType() == ColorType16 || color.ColorType() == ColorType256 {
|
||||
r0, g0, b0 := color256ToRGB(uint8(color.colorValue()))
|
||||
return NewColor24Bit(r0, g0, b0)
|
||||
}
|
||||
|
||||
panic(fmt.Errorf("unhandled color type %d", color.ColorType()))
|
||||
}
|
||||
|
||||
func (color Color) downsampleTo(terminalColorCount ColorType) Color {
|
||||
if color.ColorType() == ColorTypeDefault || terminalColorCount == ColorTypeDefault {
|
||||
panic(fmt.Errorf("downsampling to or from default color not supported, %s -> %#v", color.String(), terminalColorCount))
|
||||
@ -174,17 +186,7 @@ func (color Color) downsampleTo(terminalColorCount ColorType) Color {
|
||||
return color
|
||||
}
|
||||
|
||||
// Convert existing color to 24 bit
|
||||
var targetR float64
|
||||
var targetG float64
|
||||
var targetB float64
|
||||
if color.ColorType() == ColorType24bit {
|
||||
targetR = float64(color.colorValue()>>16) / 255.0
|
||||
targetG = float64(color.colorValue()>>8&0xff) / 255.0
|
||||
targetB = float64(color.colorValue()&0xff) / 255.0
|
||||
} else {
|
||||
targetR, targetG, targetB = color256ToRGB(uint8(color.colorValue()))
|
||||
}
|
||||
target := color.to24Bit()
|
||||
|
||||
// Find the closest match in the terminal color palette
|
||||
scanRange := 255
|
||||
@ -202,20 +204,11 @@ func (color Color) downsampleTo(terminalColorCount ColorType) Color {
|
||||
// Iterate over the scan range and find the best matching index
|
||||
bestMatch := 0
|
||||
bestDistance := math.MaxFloat64
|
||||
target := colorful.Color{
|
||||
R: targetR,
|
||||
G: targetG,
|
||||
B: targetB,
|
||||
}
|
||||
for i := 0; i <= scanRange; i++ {
|
||||
r, g, b := color256ToRGB(uint8(i))
|
||||
candidate := colorful.Color{
|
||||
R: r,
|
||||
G: g,
|
||||
B: b,
|
||||
}
|
||||
candidate := NewColor24Bit(r, g, b)
|
||||
|
||||
distance := target.DistanceLab(candidate)
|
||||
distance := target.Distance(candidate)
|
||||
if distance < bestDistance {
|
||||
bestDistance = distance
|
||||
bestMatch = i
|
||||
|
@ -1,17 +1,17 @@
|
||||
package twin
|
||||
|
||||
func color256ToRGB(color256 uint8) (r, g, b float64) {
|
||||
func color256ToRGB(color256 uint8) (r, g, b uint8) {
|
||||
if color256 < 16 {
|
||||
// Standard ANSI colors
|
||||
r := float64(standardAnsiColors[color256][0]) / 255.0
|
||||
g := float64(standardAnsiColors[color256][1]) / 255.0
|
||||
b := float64(standardAnsiColors[color256][2]) / 255.0
|
||||
r := standardAnsiColors[color256][0]
|
||||
g := standardAnsiColors[color256][1]
|
||||
b := standardAnsiColors[color256][2]
|
||||
return r, g, b
|
||||
}
|
||||
|
||||
if color256 >= 232 {
|
||||
// Grayscale. Colors 232-255 map to components 0x08 to 0xee
|
||||
gray := float64((color256-232)*0x0a+0x08) / 255.0
|
||||
gray := (color256-232)*0x0a + 0x08
|
||||
return gray, gray, gray
|
||||
}
|
||||
|
||||
@ -19,9 +19,9 @@ func color256ToRGB(color256 uint8) (r, g, b float64) {
|
||||
color0_to_215 := color256 - 16
|
||||
|
||||
components := []uint8{0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff}
|
||||
r = float64(components[(color0_to_215/36)%6]) / 255.0
|
||||
g = float64(components[(color0_to_215/6)%6]) / 255.0
|
||||
b = float64(components[(color0_to_215/1)%6]) / 255.0
|
||||
r = components[(color0_to_215/36)%6]
|
||||
g = components[(color0_to_215/6)%6]
|
||||
b = components[(color0_to_215/1)%6]
|
||||
return r, g, b
|
||||
}
|
||||
|
||||
|
@ -9,39 +9,39 @@ import (
|
||||
func TestColorRgbFirst16(t *testing.T) {
|
||||
r, g, b := color256ToRGB(5)
|
||||
|
||||
assert.Equal(t, r, float64(0x80)/255.0)
|
||||
assert.Equal(t, g, float64(0x00)/255.0)
|
||||
assert.Equal(t, b, float64(0x80)/255.0)
|
||||
assert.Equal(t, r, uint8(0x80))
|
||||
assert.Equal(t, g, uint8(0x00))
|
||||
assert.Equal(t, b, uint8(0x80))
|
||||
}
|
||||
|
||||
func TestColorToRgbInTheGrey(t *testing.T) {
|
||||
r, g, b := color256ToRGB(252)
|
||||
|
||||
assert.Equal(t, r, float64(0xd0)/255.0)
|
||||
assert.Equal(t, g, float64(0xd0)/255.0)
|
||||
assert.Equal(t, b, float64(0xd0)/255.0)
|
||||
assert.Equal(t, r, uint8(0xd0))
|
||||
assert.Equal(t, g, uint8(0xd0))
|
||||
assert.Equal(t, b, uint8(0xd0))
|
||||
}
|
||||
|
||||
func TestColorToRgbInThe6x6Cube(t *testing.T) {
|
||||
r, g, b := color256ToRGB(101)
|
||||
|
||||
assert.Equal(t, r, float64(0x87)/255.0)
|
||||
assert.Equal(t, g, float64(0x87)/255.0)
|
||||
assert.Equal(t, b, float64(0x5f)/255.0)
|
||||
assert.Equal(t, r, uint8(0x87))
|
||||
assert.Equal(t, g, uint8(0x87))
|
||||
assert.Equal(t, b, uint8(0x5f))
|
||||
}
|
||||
|
||||
func TestColorToRgbStart6x6Cube(t *testing.T) {
|
||||
r, g, b := color256ToRGB(16)
|
||||
|
||||
assert.Equal(t, r, float64(0x00)/255.0)
|
||||
assert.Equal(t, g, float64(0x00)/255.0)
|
||||
assert.Equal(t, b, float64(0x00)/255.0)
|
||||
assert.Equal(t, r, uint8(0x00))
|
||||
assert.Equal(t, g, uint8(0x00))
|
||||
assert.Equal(t, b, uint8(0x00))
|
||||
}
|
||||
|
||||
func TestColorRgbEnd6x6Cube(t *testing.T) {
|
||||
r, g, b := color256ToRGB(231)
|
||||
|
||||
assert.Equal(t, r, float64(0xff)/255.0)
|
||||
assert.Equal(t, g, float64(0xff)/255.0)
|
||||
assert.Equal(t, b, float64(0xff)/255.0)
|
||||
assert.Equal(t, r, uint8(0xff))
|
||||
assert.Equal(t, g, uint8(0xff))
|
||||
assert.Equal(t, b, uint8(0xff))
|
||||
}
|
||||
|
@ -17,10 +17,10 @@ type MouseMode int
|
||||
const (
|
||||
MouseModeAuto MouseMode = iota
|
||||
|
||||
// Don't capture mouse events. This makes marking with the mouse work. On
|
||||
// Don't capture mouse events. This makes selecting with the mouse work. On
|
||||
// some terminals mouse scrolling will work using arrow keys emulation, and
|
||||
// on some not.
|
||||
MouseModeMark
|
||||
MouseModeSelect
|
||||
|
||||
// Capture mouse events. This makes mouse scrolling work. Special gymnastics
|
||||
// will be required for marking with the mouse to copy text.
|
||||
@ -142,7 +142,7 @@ func NewScreenWithMouseModeAndColorType(mouseMode MouseMode, terminalColorCount
|
||||
|
||||
if mouseMode == MouseModeAuto {
|
||||
screen.enableMouseTracking(!terminalHasArrowKeysEmulation())
|
||||
} else if mouseMode == MouseModeMark {
|
||||
} else if mouseMode == MouseModeSelect {
|
||||
screen.enableMouseTracking(false)
|
||||
} else if mouseMode == MouseModeScroll {
|
||||
screen.enableMouseTracking(true)
|
||||
|
Loading…
Reference in New Issue
Block a user