summaryrefslogtreecommitdiffstats
path: root/up.go
blob: 55baa3b3f7564943efb6aa129b064c936c9ced7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// up is the ultimate pipe composer/editor. It helps building Linux pipelines
// in a terminal-based UI interactively, with live preview of command results.
package main

import (
	"io"
	"os"

	termbox "github.com/akavel/termbox-go"
)

const (
	queryTag  = "query"
	outputTag = "output"
)

func main() {
	// Init TUI code
	err := termbox.Init()
	if err != nil {
		panic(err)
	}
	defer termbox.Close()

	// In background, start collecting input from stdin to internal buffer of size 40 MB, then pause it
	go collect()

	for x, ch := range "hello world! :)" {
		termbox.SetCell(x, 0, ch, termbox.ColorWhite, termbox.ColorBlack)
	}
	termbox.Flush()
	for {
		switch ev := termbox.PollEvent(); ev.Type {
		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyEsc, termbox.KeyCtrlC:
				return
			}
		}
	}

	// // Init TUI code
	// tui, err := tcell.NewScreen()
	// if err != nil {
	// 	panic(err)
	// }
	// err = tui.Init()
	// if err != nil {
	// 	panic(err)
	// }
	// defer tui.Fini()
	// // FIXME: wide rune support, combining marks, etc.
	// for x, ch := range "hello world! :)" {
	// 	tui.SetContent(x, 0, ch, nil, tcell.StyleDefault)
	// }
	// for {
	// 	event := tui.PollEvent()
	// 	switch event := event.(type) {
	// 	case *tcell.EventError:
	// 		panic(event)
	// 	case *tcell.EventKey:
	// 		switch event.Key() {
	// 		case tcell.KeyCtrlC, tcell.KeyEsc:
	// 			return
	// 		case tcell.KeyRune:
	// 			if event.Rune() == 'q' {
	// 				return
	// 			}
	// 		}
	// 	}
	// }

	// tui, err := gocui.NewGui(gocui.OutputNormal)
	// if err != nil {
	// 	panic(err)
	// }
	// defer tui.Close()

	// Prepare TUI layout etc.

	// tui.SetManagerFunc(layout)
	// w, h := tui.Size()
	// query, err := tui.SetView(queryTag, 0, 0, w-1, 3)
	// if err != nil && err != gocui.ErrUnknownView {
	// 	panic(err)
	// }
	// query.Title = "Command"
	// query.BgColor = gocui.ColorCyan
	// query.Editable = true
	// // query.Editor = gocui.DefaultEditor
	// output, err := tui.SetView(outputTag, 0, 3, w-1, h-1)
	// if err != nil && err != gocui.ErrUnknownView {
	// 	panic(err)
	// }
	// output.Title = "Output"
	// output.Autoscroll = true
	// err = tui.SetKeybinding(queryTag, gocui.KeyCtrlC, gocui.ModNone, func(*gocui.Gui, *gocui.View) error {
	// 	return gocui.ErrQuit
	// })
	// if err != nil {
	// 	panic(err)
	// }
	// tui.SetCurrentView(queryTag)
	// err = tui.MainLoop()
	// if err != nil && err != gocui.ErrQuit {
	// 	panic(err)
	// }

	// TODO: using tcell, edit a command in bash format in multiline input box (or jroimartin/gocui?)
	//       NOTE: gocui has trouble if we capture stdin. Try butchering ("total modding") peco/peco instead.
	// TODO: run it automatically in bg after first " " (or ^Enter), via `bash -c`
	// TODO: auto-kill the child process on any edit
	// TODO: [LATER] Ctrl-O shows input via `less` or $PAGER
	// TODO: ^X - save into executable file upN.sh (with #!/bin/bash) and quit
	// TODO: [LATER] allow increasing size of input buffer with some key
	// TODO: [LATER] on ^X, leave TUI and run the command through buffered input, then unpause rest of input
	// TODO: [LATER] allow adding more elements of pipeline (initially, just writing `foo | bar` should work)
	// TODO: [LATER] allow invocation with partial command, like: `up grep -i`
	// TODO: [LATER][MAYBE] allow reading upN.sh scripts
	// TODO: [LATER] auto-save and/or save on Ctrl-S or something
	// TODO: [MUCH LATER] readline-like rich editing support? and completion?
	// TODO: [MUCH LATER] integration with fzf? and pindexis/marker?
	// TODO: [LATER] forking and unforking pipelines
	// TODO: [LATER] capture output of a running process (see: https://stackoverflow.com/q/19584825/98528)
	// TODO: [LATER] richer TUI:
	// - show # of read lines & kbytes
	// - show status (errorlevel) of process, or that it's still running (also with background colors)
	// - allow copying and pasting to/from command line
	// TODO: [LATER] allow connecting external editor (become server/engine via e.g. socket)
	// TODO: [LATER] become pluggable into http://luna-lang.org
	// TODO: [LATER][MAYBE] allow "plugins" ("combos" - commands with default options) e.g. for Lua `lua -e`+auto-quote, etc.
	// TODO: [LATER] make it more friendly to infrequent Linux users by providing "descriptive" commands like "search" etc.
	// TODO: [LATER] advertise on: HN, r/programming, r/golang, r/commandline, r/linux; data exploration? data science?
}

func collect() {
	const bufsize = 40 * 1024 * 1024 // 40 MB
	buf := make([]byte, bufsize)
	// TODO: read gradually what is available and show progress
	n, err := io.ReadFull(os.Stdin, buf)
	if err != nil && err != io.ErrUnexpectedEOF {
		panic(err)
	}
	buf = buf[:n]
	// TODO: use buf somewhere
}

// func layout(tui *gocui.Gui) error {
// 	// w, h := tui.Size()
// 	return nil
// }