Initial version

This commit is contained in:
Laurence Withers 2023-04-07 16:32:39 +01:00
parent 380cb01dc1
commit d664931113
8 changed files with 135 additions and 2 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/missingnewline

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) <year> <copyright holders>
Copyright (c) 2023 Laurence Withers.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,3 +1,17 @@
# missingnewline
Prints a "🚫" character and adds a newline if the cursor is not in column 1. You can use it in your shell prompt to tidy up after commands that output some text without a trailing newline.
Prints a "🚫" character and adds a newline if the cursor is not in column 1.
You can use it in your shell prompt to tidy up after commands that output some
text without a trailing newline.
![Example terminal session showing the problem of an unterminated command mixing with the shell prompt, and then the program correctly detecting the presence or absence of a non-newline-terminated output and using the "🚫" character appropriately.](example.gif)
You can install this into your `~/.bashrc`, for example:
```
declare -a PROMPT_COMMAND
if [ -x "${HOME}/go/bin/missingnewline" ]
then
PROMPT_COMMAND+=("${HOME}/go/bin/missingnewline")
fi
```

BIN
example.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

8
go.mod Normal file
View File

@ -0,0 +1,8 @@
module src.lwithers.me.uk/go/missingnewline
go 1.20
require (
golang.org/x/sys v0.7.0
golang.org/x/term v0.7.0
)

4
go.sum Normal file
View File

@ -0,0 +1,4 @@
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=

106
main.go Normal file
View File

@ -0,0 +1,106 @@
package main
import (
"bytes"
"fmt"
"os"
"strconv"
"strings"
"time"
"golang.org/x/sys/unix"
"golang.org/x/term"
)
func main() {
st, err := term.MakeRaw(0)
if err != nil {
os.Exit(1)
}
var column int
select {
case <-time.After(100 * time.Millisecond):
case column = <-awaitColumn():
}
term.Restore(0, st)
if column > 1 {
unix.Write(1, []byte("🚫\n")) // U+1F6AB
}
}
func awaitColumn() <-chan int {
ch := make(chan int)
go func() {
row, col := readDSR()
_ = row
ch <- col
}()
return ch
}
func readDSR() (row, col int) {
unix.Write(1, []byte{
'\033', '[', // ANSI escape code: CSI
'6', 'n', // DSR / device status report
})
buf := make([]byte, 64)
n, err := unix.Read(0, buf)
if err != nil {
return 0, 0
}
buf = buf[:n]
if len(buf) < 6 || buf[0] != '\033' || buf[1] != '[' || buf[len(buf)-1] != 'R' {
return 0, 0
}
s := string(buf[2 : len(buf)-1])
pos := strings.IndexByte(s, ';')
if pos == -1 {
return 0, 0
}
row, err = strconv.Atoi(s[:pos])
if err != nil {
return 0, 0
}
col, err = strconv.Atoi(s[pos+1:])
if err != nil {
return 0, 0
}
return row, col
}
func processit(b []byte) {
if !bytes.HasPrefix(b, []byte{'\033', '['}) {
return
}
if !bytes.HasSuffix(b, []byte{'R'}) {
return
}
s := string(b[2 : len(b)-1])
pos := strings.IndexByte(s, ';')
if pos == -1 {
return
}
x, err := strconv.Atoi(s[pos+1:])
if err != nil {
return
}
if x != 1 {
fmt.Println("🚫") // U+1F6AB
}
}
func readit() chan []byte {
q := make(chan []byte)
go func() {
b := make([]byte, 1024)
n, _ := os.Stdin.Read(b)
q <- b[:n]
}()
return q
}

BIN
my-recording Normal file

Binary file not shown.