Added shell execution
This commit is contained in:
parent
23d6ad2ab9
commit
49e4cb7bd2
22
core/ConfigDir.go
Normal file
22
core/ConfigDir.go
Normal file
@ -0,0 +1,22 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func ConfigDir() string {
|
||||
home := os.Getenv("XDG_CONFIG_HOME")
|
||||
|
||||
if home != "" {
|
||||
return filepath.Join(home, "dash")
|
||||
}
|
||||
|
||||
home, err := os.UserHomeDir()
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return filepath.Join(home, ".config", "dash")
|
||||
}
|
28
core/Process.go
Normal file
28
core/Process.go
Normal file
@ -0,0 +1,28 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
sh = regexp.MustCompile("\\{([^\\}]+)\\}")
|
||||
)
|
||||
|
||||
func Process(source string) string {
|
||||
source = sh.ReplaceAllStringFunc(source, func(match string) string {
|
||||
cmd := sh.FindStringSubmatch(match)[1]
|
||||
args := strings.Fields(cmd)
|
||||
shellArgs := []string{"-c", strings.Join(args, " ")}
|
||||
output, err := exec.Command("sh", shellArgs...).CombinedOutput()
|
||||
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return strings.Trim(string(output), "\n")
|
||||
})
|
||||
|
||||
return source
|
||||
}
|
155
editor/editor.go
155
editor/editor.go
@ -2,60 +2,155 @@ package editor
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"git.akyoto.dev/cli/dash/core"
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
func New(app *tview.Application) *tview.TextArea {
|
||||
view := tview.NewTextArea()
|
||||
view.SetBackgroundColor(tcell.ColorDefault)
|
||||
view.SetTextStyle(tcell.StyleDefault)
|
||||
view.SetBorderPadding(0, 0, 1, 1)
|
||||
source := "Having been erased,\nThe document you're seeking\nMust now be retyped."
|
||||
type Editor struct {
|
||||
Pages *tview.Pages
|
||||
Source *tview.TextArea
|
||||
Result *tview.TextView
|
||||
FilePath string
|
||||
IsDirty bool
|
||||
}
|
||||
|
||||
home, err := os.UserHomeDir()
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
func New(app *tview.Application, filePath string) *Editor {
|
||||
e := &Editor{
|
||||
FilePath: filePath,
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(filepath.Join(home, ".dash"))
|
||||
e.Pages = tview.NewPages()
|
||||
e.Pages.SetBackgroundColor(tcell.ColorDefault)
|
||||
|
||||
if err == nil {
|
||||
source = string(data)
|
||||
source := e.newSourceEditor()
|
||||
result := e.newResult()
|
||||
|
||||
e.Pages.AddPage("Source", source, true, false)
|
||||
e.Pages.AddPage("Result", result, true, true)
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Editor) toggle() {
|
||||
front, _ := e.Pages.GetFrontPage()
|
||||
|
||||
switch front {
|
||||
case "Source":
|
||||
e.Pages.SwitchToPage("Result")
|
||||
case "Result":
|
||||
e.Pages.SwitchToPage("Source")
|
||||
}
|
||||
}
|
||||
|
||||
view.SetText(source, true)
|
||||
func (e *Editor) newSourceEditor() *tview.TextArea {
|
||||
e.Source = tview.NewTextArea()
|
||||
e.Source.SetBackgroundColor(tcell.ColorDefault)
|
||||
e.Source.SetTextStyle(tcell.StyleDefault)
|
||||
e.Source.SetBorderPadding(0, 0, 1, 1)
|
||||
e.load()
|
||||
|
||||
view.SetChangedFunc(func() {
|
||||
source = view.GetText()
|
||||
markDirty(view, true)
|
||||
e.Source.SetChangedFunc(func() {
|
||||
e.setDirty(true)
|
||||
})
|
||||
|
||||
view.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||
e.Source.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||
if event.Key() == tcell.KeyESC {
|
||||
e.updateResult()
|
||||
e.toggle()
|
||||
return nil
|
||||
}
|
||||
|
||||
if event.Key() == tcell.KeyCtrlS {
|
||||
err := os.WriteFile(filepath.Join(home, ".dash"), []byte(source), 0644)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
markDirty(view, false)
|
||||
e.save()
|
||||
e.updateResult()
|
||||
e.toggle()
|
||||
return nil
|
||||
}
|
||||
|
||||
return event
|
||||
})
|
||||
|
||||
return view
|
||||
return e.Source
|
||||
}
|
||||
|
||||
func markDirty(view *tview.TextArea, dirty bool) {
|
||||
func (e *Editor) newResult() *tview.TextView {
|
||||
e.Result = tview.NewTextView()
|
||||
e.Result.SetBackgroundColor(tcell.ColorDefault)
|
||||
e.Result.SetTextStyle(tcell.StyleDefault)
|
||||
e.Result.SetBorderPadding(0, 0, 1, 1)
|
||||
|
||||
e.Result.SetMouseCapture(func(action tview.MouseAction, event *tcell.EventMouse) (tview.MouseAction, *tcell.EventMouse) {
|
||||
if action == tview.MouseLeftClick {
|
||||
e.toggle()
|
||||
}
|
||||
|
||||
return action, event
|
||||
})
|
||||
|
||||
e.Result.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||
switch event.Key() {
|
||||
case tcell.KeyEnter:
|
||||
e.toggle()
|
||||
return nil
|
||||
|
||||
case tcell.KeyRune:
|
||||
if event.Rune() == 'i' {
|
||||
e.toggle()
|
||||
return nil
|
||||
}
|
||||
|
||||
case tcell.KeyCtrlS:
|
||||
e.save()
|
||||
return nil
|
||||
}
|
||||
|
||||
return event
|
||||
})
|
||||
|
||||
e.updateResult()
|
||||
return e.Result
|
||||
}
|
||||
|
||||
func (e *Editor) updateResult() {
|
||||
source := e.Source.GetText()
|
||||
result := core.Process(source)
|
||||
e.Result.SetText(result)
|
||||
}
|
||||
|
||||
func (e *Editor) setDirty(dirty bool) {
|
||||
e.IsDirty = dirty
|
||||
|
||||
if dirty {
|
||||
view.SetBackgroundColor(tcell.ColorRed)
|
||||
e.Source.SetBackgroundColor(tcell.ColorRed)
|
||||
} else {
|
||||
view.SetBackgroundColor(tcell.ColorDefault)
|
||||
e.Source.SetBackgroundColor(tcell.ColorDefault)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Editor) load() {
|
||||
source := "Press Enter to edit.\nPress Esc to preview.\nPress Ctrl + S to save.\n\n{whoami}@{hostname}"
|
||||
data, err := os.ReadFile(e.FilePath)
|
||||
|
||||
if err == nil {
|
||||
source = string(data)
|
||||
}
|
||||
|
||||
e.Source.SetText(source, true)
|
||||
}
|
||||
|
||||
func (e *Editor) save() {
|
||||
if !e.IsDirty {
|
||||
return
|
||||
}
|
||||
|
||||
source := e.Source.GetText()
|
||||
err := os.WriteFile(e.FilePath, []byte(source), 0600)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
e.setDirty(false)
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
package empty
|
||||
|
||||
import (
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
func New(app *tview.Application) *tview.Box {
|
||||
view := tview.NewBox()
|
||||
view.SetBackgroundColor(tcell.ColorDefault)
|
||||
view.SetBorderPadding(1, 1, 1, 1)
|
||||
return view
|
||||
}
|
38
main.go
38
main.go
@ -1,9 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"git.akyoto.dev/cli/dash/clock"
|
||||
"git.akyoto.dev/cli/dash/core"
|
||||
"git.akyoto.dev/cli/dash/editor"
|
||||
//"git.akyoto.dev/cli/dash/empty"
|
||||
"git.akyoto.dev/cli/dash/osinfo"
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
@ -12,37 +15,32 @@ import (
|
||||
func main() {
|
||||
app := tview.NewApplication()
|
||||
|
||||
header := clock.New(app)
|
||||
main := editor.New(app)
|
||||
footer := osinfo.New(app)
|
||||
//left := empty.New(app)
|
||||
//right := empty.New(app)
|
||||
|
||||
grid := tview.NewGrid()
|
||||
grid.SetRows(3, 0, 3)
|
||||
grid.SetColumns(0, 80, 0)
|
||||
grid.SetBorders(false)
|
||||
grid.SetBackgroundColor(tcell.ColorDefault)
|
||||
|
||||
dataDir := core.ConfigDir()
|
||||
err := os.MkdirAll(dataDir, 0700)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
header := clock.New(app)
|
||||
main := editor.New(app, filepath.Join(dataDir, "main"))
|
||||
footer := osinfo.New(app)
|
||||
|
||||
grid.AddItem(header, 0, 0, 1, 3, 0, 0, false)
|
||||
grid.AddItem(main, 1, 1, 1, 1, 0, 0, false)
|
||||
grid.AddItem(main.Pages, 1, 1, 1, 1, 0, 0, false)
|
||||
grid.AddItem(footer, 2, 0, 1, 3, 0, 0, false)
|
||||
|
||||
// Layout for screens narrower than 100 cells (menu and side bar are hidden).
|
||||
//grid.AddItem(left, 0, 0, 0, 0, 0, 0, false)
|
||||
//grid.AddItem(main, 1, 0, 1, 3, 0, 0, false)
|
||||
//grid.AddItem(right, 0, 0, 0, 0, 0, 0, false)
|
||||
|
||||
// Layout for screens wider than 80 cells.
|
||||
//grid.AddItem(left, 1, 0, 1, 1, 0, 80, false)
|
||||
//grid.AddItem(main, 1, 1, 1, 1, 0, 80, false)
|
||||
//grid.AddItem(right, 1, 2, 1, 1, 0, 80, false)
|
||||
|
||||
app.EnableMouse(true)
|
||||
app.SetRoot(grid, true)
|
||||
app.SetFocus(main)
|
||||
app.SetFocus(main.Pages)
|
||||
|
||||
err := app.Run()
|
||||
err = app.Run()
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
Loading…
Reference in New Issue
Block a user