shithub: hell

ref: 7235fc1225901e80e0058acdc3db9b67e9a36338
dir: /readline_plan9.go/

View raw version
package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"
	"image"

    "codeberg.org/penny64/go/draw"
	"codeberg.org/penny64/go/draw/frame"
)

// not relevant
const (
	CharCtrlJ     = 0
	CharInterrupt = 0
	CharEnter     = 0
)

type readline struct {
	config Config
	multi  bool
	ctl    *os.File
	label *os.File
}

type Config struct {
	Prompt string

	//These are unused on Plan 9
	FuncFilterInputRune func(rune) (rune, bool)
	Listener            func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool)
}

func (rl *readline) GetConfig() *Config {
	return &Config{Prompt: rl.config.Prompt}
}

func NewReadline(config *Config) (*readline, error) {
	window, err := draw.Init(nil, "", "hell", "")
	if err != nil {
		return nil, err
	}

	var maincols [frame.NCOL]*draw.Image
	/* Main text is yellowish */
	screen := window.ScreenImage
	maincols[frame.BACK] = window.AllocImageMix(draw.PaleYellow, draw.White)
	maincols[frame.HIGH], _ = window.AllocImage(image.Rect(0, 0, 1, 1), screen.Pix, true, draw.DarkYellow)
	maincols[frame.BORD], _ = window.AllocImage(image.Rect(0, 0, 2, 2), screen.Pix, true, draw.YellowGreen)
	maincols[frame.TEXT] = window.Black
	maincols[frame.HTEXT] = window.Black

	const (
		ScrollbarWidth = 12
		BorderWidth    = 2
	)
	fullRect := window.ScreenImage.R
	window.ScreenImage.Draw(fullRect, maincols[frame.BACK], nil, draw.ZP)
	scrollRect := fullRect
	scrollRect.Max.X = scrollRect.Min.X + ScrollbarWidth
	textRect := fullRect
	textRect.Min.X = scrollRect.Max.X
	window.ScreenImage.Border(textRect, BorderWidth, maincols[frame.BORD], draw.ZP)
	frameRect := textRect.Inset(BorderWidth)
	f := &frame.Frame{}
	f.Init(frameRect, window.Font, window.ScreenImage, maincols[:])
	f.Insert([]rune("Hello, Frame!"), 0)
	f.Display = window
	f.InitTick()
	f.Tick(f.PointOf(f.NumChars), true)
	window.ScreenImage.Draw(scrollRect, maincols[frame.TEXT], nil, draw.ZP)

	window.Flush()
	label, err := os.OpenFile("/dev/label", os.O_WRONLY, 0)
	return &readline{config: *config, ctl: nil, label: label}, nil
}

func (rl *readline) ReadLineWithConfig(cfg *Config) (string, error) {
	if rl.multi {
		fmt.Print("MULTILINE ")
	}
	fmt.Print(cfg.Prompt)
	var sb strings.Builder
	var err error
	var input string
	for {
		buffer := bufio.NewReader(os.Stdin)
		input, err = buffer.ReadString('\n')
		sb.WriteString(input)
		if err != nil {
			rl.multi = !rl.multi
			if rl.multi {
				fmt.Printf("MULTILINE %s", cfg.Prompt)
				rl.ctl.WriteString("holdon")
				continue
			}
		}
		if !rl.multi {
			break
		}
	}
	return strings.TrimSpace(sb.String()), err
}

func (rl *readline) Stdout() io.Writer {
	return os.Stdout
}

func (rl *readline) Close() {
	return
}

func (rl *readline) SetPrompt(prompt string) {
	rl.config.Prompt = prompt
}

func (rl *readline) SetDefault(editline string) {
	rl.multi = true
	rl.ctl.WriteString("holdon")
	fmt.Printf("%s\n\n", editline)
}

func (rl *readline) Readline() (string, error) {
	return rl.ReadLineWithConfig(&rl.config)
}

func enablePipeHack(rl *readline) {
}

func (rl *readline) setWindowTitle(title string) {
	rl.label.WriteString(title)
}