diff --git a/README.md b/README.md index 92954b1..7387788 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ Ensure you have your latest graphics card drivers installed before use. | Operation | Key(s) | |--------------------|---------------------| | Paste | ctrl + shift + v +| Toggle slomo | ctrl + shift + ; | Interrupt (SIGINT) | ctrl + c ## Configuration diff --git a/buffer/buffer.go b/buffer/buffer.go index 8e43852..30d97b7 100644 --- a/buffer/buffer.go +++ b/buffer/buffer.go @@ -342,8 +342,8 @@ func (buffer *Buffer) Clear() { // creates if necessary func (buffer *Buffer) getCurrentLine() *Line { - if buffer.cursorY >= buffer.ViewHeight() { - panic(fmt.Sprintf("cursor is outside of view: y=%d h=%d", buffer.cursorY, buffer.viewHeight)) + if buffer.cursorY >= buffer.ViewHeight() { // @todo is this okay? + return &buffer.lines[len(buffer.lines)-1] } if len(buffer.lines) < int(buffer.ViewHeight()) { diff --git a/fonts/DejaVuSansMono.ttf b/fonts/DejaVuSansMono.ttf new file mode 100644 index 0000000..f578602 Binary files /dev/null and b/fonts/DejaVuSansMono.ttf differ diff --git a/gui/gui.go b/gui/gui.go index ca20caf..080caab 100644 --- a/gui/gui.go +++ b/gui/gui.go @@ -17,7 +17,7 @@ import ( type GUI struct { window *glfw.Window logger *zap.SugaredLogger - config config.Config + config *config.Config terminal *terminal.Terminal width int //window width in pixels height int //window height in pixels @@ -27,7 +27,7 @@ type GUI struct { colourAttr uint32 } -func New(config config.Config, terminal *terminal.Terminal, logger *zap.SugaredLogger) *GUI { +func New(config *config.Config, terminal *terminal.Terminal, logger *zap.SugaredLogger) *GUI { //logger. return &GUI{ diff --git a/gui/input.go b/gui/input.go index cc473c7..fd37b66 100644 --- a/gui/input.go +++ b/gui/input.go @@ -23,6 +23,8 @@ func (gui *GUI) key(w *glfw.Window, key glfw.Key, scancode int, action glfw.Acti if buf, err := gui.window.GetClipboardString(); err == nil { _ = gui.terminal.Write([]byte(buf)) } + case glfw.KeySemicolon: + gui.config.Slomo = !gui.config.Slomo } } else { // ctrl + diff --git a/gui/mouse.go b/gui/mouse.go index 71132c9..e7d1986 100644 --- a/gui/mouse.go +++ b/gui/mouse.go @@ -38,10 +38,10 @@ func (gui *GUI) mouseButtonCallback(w *glfw.Window, button glfw.MouseButton, act */ if action == glfw.Press { - b := rune(button & 0xff) - x := rune((gui.terminal.ActiveBuffer().CursorColumn() + 31) & 0xff) - y := rune((gui.terminal.ActiveBuffer().CursorLine() + 31) & 0xff) - packet := fmt.Sprintf("\x1b[%cb%cx%cyM", b, x, y) + b := rune(byte(button & 0xff)) + x := rune(byte((gui.terminal.ActiveBuffer().CursorColumn() + 31) & 0xff)) + y := rune(byte((gui.terminal.ActiveBuffer().CursorLine() + 31) & 0xff)) + packet := fmt.Sprintf("\x1b[%c%c%cM", b, x, y) gui.terminal.Write([]byte(packet)) } case terminal.MouseModeVT200: // normal @@ -93,9 +93,9 @@ func (gui *GUI) mouseButtonCallback(w *glfw.Window, button glfw.MouseButton, act if mod&glfw.ModControl > 0 { b |= 16 } - x := rune((gui.terminal.ActiveBuffer().CursorColumn() + 31) & 0xff) - y := rune((gui.terminal.ActiveBuffer().CursorLine() + 31) & 0xff) - packet := fmt.Sprintf("\x1b[%cb%cx%cyM", b, x, y) + x := rune(byte((gui.terminal.ActiveBuffer().CursorColumn() + 31) & 0xff)) + y := rune(byte((gui.terminal.ActiveBuffer().CursorLine() + 31) & 0xff)) + packet := fmt.Sprintf("\x1b[%c%c%cM", b, x, y) gui.terminal.Write([]byte(packet)) case terminal.MouseModeVT200Highlight: diff --git a/gui/renderer.go b/gui/renderer.go index 034e92d..4410eec 100644 --- a/gui/renderer.go +++ b/gui/renderer.go @@ -31,7 +31,7 @@ type OpenGLRenderer struct { termRows uint cellPositions map[[2]uint][2]float32 rectangles map[[2]uint]*rectangle - config config.Config + config *config.Config colourAttr uint32 program uint32 } @@ -117,7 +117,7 @@ func (rect *rectangle) Free() { gl.DeleteBuffers(1, &rect.cv) } -func NewOpenGLRenderer(config config.Config, font *glfont.Font, fontScale int32, areaX int, areaY int, areaWidth int, areaHeight int, colourAttr uint32, program uint32) *OpenGLRenderer { +func NewOpenGLRenderer(config *config.Config, font *glfont.Font, fontScale int32, areaX int, areaY int, areaWidth int, areaHeight int, colourAttr uint32, program uint32) *OpenGLRenderer { r := &OpenGLRenderer{ areaWidth: areaWidth, areaHeight: areaHeight, diff --git a/main.go b/main.go index 0ffe0db..14a70be 100644 --- a/main.go +++ b/main.go @@ -13,11 +13,11 @@ import ( "go.uber.org/zap" ) -func getConfig() config.Config { +func getConfig() *config.Config { ignore := false flag.BoolVar(&ignore, "ignore-config", ignore, "Ignore user config files and use defauls") if ignore { - return config.DefaultConfig + return &config.DefaultConfig } conf := loadConfigFile() @@ -30,11 +30,11 @@ func getConfig() config.Config { return conf } -func loadConfigFile() config.Config { +func loadConfigFile() *config.Config { home := os.Getenv("HOME") if home == "" { - return config.DefaultConfig + return &config.DefaultConfig } places := []string{ @@ -45,7 +45,7 @@ func loadConfigFile() config.Config { for _, place := range places { if b, err := ioutil.ReadFile(place); err == nil { if c, err := config.Parse(b); err == nil { - return *c + return c } else { fmt.Printf("Invalid config at %s: %s\n", place, err) } @@ -59,10 +59,10 @@ func loadConfigFile() config.Config { fmt.Printf("Failed to encode config file: %s\n", err) } } - return config.DefaultConfig + return &config.DefaultConfig } -func getLogger(conf config.Config) (*zap.SugaredLogger, error) { +func getLogger(conf *config.Config) (*zap.SugaredLogger, error) { var logger *zap.Logger var err error diff --git a/shit.sh b/shit.sh new file mode 100755 index 0000000..99e3d8c --- /dev/null +++ b/shit.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +# Tom Hale, 2016. MIT Licence. +# Print out 256 colours, with each number printed in its corresponding colour +# See http://askubuntu.com/questions/821157/print-a-256-color-test-pattern-in-the-terminal/821163#821163 + +set -eu # Fail on errors or undeclared variables + +printable_colours=256 + +# Return a colour that contrasts with the given colour +# Bash only does integer division, so keep it integral +function contrast_colour { + local r g b luminance + colour="$1" + + if (( colour < 16 )); then # Initial 16 ANSI colours + (( colour == 0 )) && printf "15" || printf "0" + return + fi + + # Greyscale # rgb_R = rgb_G = rgb_B = (number - 232) * 10 + 8 + if (( colour > 231 )); then # Greyscale ramp + (( colour < 244 )) && printf "15" || printf "0" + return + fi + + # All other colours: + # 6x6x6 colour cube = 16 + 36*R + 6*G + B # Where RGB are [0..5] + # See http://stackoverflow.com/a/27165165/5353461 + + # r=$(( (colour-16) / 36 )) + g=$(( ((colour-16) % 36) / 6 )) + # b=$(( (colour-16) % 6 )) + + # If luminance is bright, print number in black, white otherwise. + # Green contributes 587/1000 to human perceived luminance - ITU R-REC-BT.601 + (( g > 2)) && printf "0" || printf "15" + return + + # Uncomment the below for more precise luminance calculations + + # # Calculate percieved brightness + # # See https://www.w3.org/TR/AERT#color-contrast + # # and http://www.itu.int/rec/R-REC-BT.601 + # # Luminance is in range 0..5000 as each value is 0..5 + # luminance=$(( (r * 299) + (g * 587) + (b * 114) )) + # (( $luminance > 2500 )) && printf "0" || printf "15" +} + +# Print a coloured block with the number of that colour +function print_colour { + local colour="$1" contrast + contrast=$(contrast_colour "$1") + printf "\e[48;5;%sm" "$colour" # Start block of colour + printf "\e[38;5;%sm%3d" "$contrast" "$colour" # In contrast, print number + printf "\e[0m " # Reset colour +} + +# Starting at $1, print a run of $2 colours +function print_run { + local i + for (( i = "$1"; i < "$1" + "$2" && i < printable_colours; i++ )) do + print_colour "$i" + done + printf " " +} + +# Print blocks of colours +function print_blocks { + local start="$1" i + local end="$2" # inclusive + local block_cols="$3" + local block_rows="$4" + local blocks_per_line="$5" + local block_length=$((block_cols * block_rows)) + + # Print sets of blocks + for (( i = start; i <= end; i += (blocks_per_line-1) * block_length )) do + printf "\n" # Space before each set of blocks + # For each block row + for (( row = 0; row < block_rows; row++ )) do + # Print block columns for all blocks on the line + for (( block = 0; block < blocks_per_line; block++ )) do + print_run $(( i + (block * block_length) )) "$block_cols" + done + (( i += block_cols )) # Prepare to print the next row + printf "\n" + done + done +} + +print_run 0 16 # The first 16 colours are spread over the whole spectrum +printf "\n" +print_blocks 16 231 6 6 3 # 6x6x6 colour cube between 16 and 231 inclusive +print_blocks 232 255 12 2 1 # Not 50, but 24 Shades of Grey diff --git a/terminal/csi.go b/terminal/csi.go index cf5ae68..b71a5cd 100644 --- a/terminal/csi.go +++ b/terminal/csi.go @@ -88,7 +88,7 @@ func csiSetMode(modeStr string, enabled bool, terminal *Terminal) error { } else { terminal.UseMainBuffer() } - case "?1000": + case "?1000", "?10061000": // ?10061000 seen from xterm // enable mouse tracking if enabled { terminal.SetMouseMode(MouseModeVT200) diff --git a/terminal/output.go b/terminal/output.go index 0b2e423..0f4faf7 100644 --- a/terminal/output.go +++ b/terminal/output.go @@ -2,6 +2,7 @@ package terminal import ( "context" + "time" ) // Wish list here: http://invisible-island.net/xterm/ctlseqs/ctlseqs.html @@ -30,8 +31,9 @@ func (terminal *Terminal) processInput(ctx context.Context, pty chan rune) { default: } - //if terminal.config.slomo - //time.Sleep(time.Millisecond * 100) + if terminal.config.Slomo { + time.Sleep(time.Millisecond * 100) + } b := <-pty diff --git a/terminal/terminal.go b/terminal/terminal.go index 138a39b..4410eac 100644 --- a/terminal/terminal.go +++ b/terminal/terminal.go @@ -39,7 +39,7 @@ type Terminal struct { logger *zap.SugaredLogger title string size Winsize - config config.Config + config *config.Config titleHandlers []chan bool pauseChan chan bool resumeChan chan bool @@ -65,7 +65,7 @@ type Position struct { Col int } -func New(pty *os.File, logger *zap.SugaredLogger, config config.Config) *Terminal { +func New(pty *os.File, logger *zap.SugaredLogger, config *config.Config) *Terminal { return &Terminal{ buffers: []*buffer.Buffer{ @@ -246,20 +246,3 @@ func (terminal *Terminal) SetSize(newCols uint, newLines uint) error { return nil } - -/* ------------------- -> -ssssssssssssssssss -ssssPPPPPPPPPPPPPP -xxxxxxxxx -xxxxxxxxxxxxxxxxxx --------------------------- -ssssssssssssssssss -SsssPPPPPPPPPPPPPP -xxxxxxxxx -xxxxxxxxxxxxxxxxxx - - - - -*/