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 (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
|
"git.akyoto.dev/cli/dash/core"
|
||||||
"github.com/gdamore/tcell/v2"
|
"github.com/gdamore/tcell/v2"
|
||||||
"github.com/rivo/tview"
|
"github.com/rivo/tview"
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(app *tview.Application) *tview.TextArea {
|
type Editor struct {
|
||||||
view := tview.NewTextArea()
|
Pages *tview.Pages
|
||||||
view.SetBackgroundColor(tcell.ColorDefault)
|
Source *tview.TextArea
|
||||||
view.SetTextStyle(tcell.StyleDefault)
|
Result *tview.TextView
|
||||||
view.SetBorderPadding(0, 0, 1, 1)
|
FilePath string
|
||||||
source := "Having been erased,\nThe document you're seeking\nMust now be retyped."
|
IsDirty bool
|
||||||
|
}
|
||||||
|
|
||||||
home, err := os.UserHomeDir()
|
func New(app *tview.Application, filePath string) *Editor {
|
||||||
|
e := &Editor{
|
||||||
if err != nil {
|
FilePath: filePath,
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := os.ReadFile(filepath.Join(home, ".dash"))
|
e.Pages = tview.NewPages()
|
||||||
|
e.Pages.SetBackgroundColor(tcell.ColorDefault)
|
||||||
|
|
||||||
if err == nil {
|
source := e.newSourceEditor()
|
||||||
source = string(data)
|
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() {
|
e.Source.SetChangedFunc(func() {
|
||||||
source = view.GetText()
|
e.setDirty(true)
|
||||||
markDirty(view, 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 {
|
if event.Key() == tcell.KeyCtrlS {
|
||||||
err := os.WriteFile(filepath.Join(home, ".dash"), []byte(source), 0644)
|
e.save()
|
||||||
|
e.updateResult()
|
||||||
if err != nil {
|
e.toggle()
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
markDirty(view, false)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return event
|
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 {
|
if dirty {
|
||||||
view.SetBackgroundColor(tcell.ColorRed)
|
e.Source.SetBackgroundColor(tcell.ColorRed)
|
||||||
} else {
|
} 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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"git.akyoto.dev/cli/dash/clock"
|
"git.akyoto.dev/cli/dash/clock"
|
||||||
|
"git.akyoto.dev/cli/dash/core"
|
||||||
"git.akyoto.dev/cli/dash/editor"
|
"git.akyoto.dev/cli/dash/editor"
|
||||||
//"git.akyoto.dev/cli/dash/empty"
|
|
||||||
"git.akyoto.dev/cli/dash/osinfo"
|
"git.akyoto.dev/cli/dash/osinfo"
|
||||||
"github.com/gdamore/tcell/v2"
|
"github.com/gdamore/tcell/v2"
|
||||||
"github.com/rivo/tview"
|
"github.com/rivo/tview"
|
||||||
@ -12,37 +15,32 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
app := tview.NewApplication()
|
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 := tview.NewGrid()
|
||||||
grid.SetRows(3, 0, 3)
|
grid.SetRows(3, 0, 3)
|
||||||
grid.SetColumns(0, 80, 0)
|
grid.SetColumns(0, 80, 0)
|
||||||
grid.SetBorders(false)
|
grid.SetBorders(false)
|
||||||
grid.SetBackgroundColor(tcell.ColorDefault)
|
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(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)
|
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.EnableMouse(true)
|
||||||
app.SetRoot(grid, true)
|
app.SetRoot(grid, true)
|
||||||
app.SetFocus(main)
|
app.SetFocus(main.Pages)
|
||||||
|
|
||||||
err := app.Run()
|
err = app.Run()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
Loading…
Reference in New Issue
Block a user