Skip to content

Commit

Permalink
[WIP] Add BubbleTea TUI
Browse files Browse the repository at this point in the history
Signed-off-by: egibs <20933572+egibs@users.noreply.github.com>
  • Loading branch information
egibs committed Dec 7, 2024
1 parent 37649a8 commit 62ec80f
Show file tree
Hide file tree
Showing 15 changed files with 782 additions and 13 deletions.
22 changes: 12 additions & 10 deletions cmd/mal/mal.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ func main() {
&cli.StringFlag{
Name: "format",
Value: "auto",
Usage: "Output format (json, markdown, simple, strings, terminal, yaml)",
Usage: "Output format (json, markdown, simple, strings, terminal, tui, yaml)",
Destination: &formatFlag,
},
&cli.BoolFlag{
Expand Down Expand Up @@ -536,25 +536,27 @@ func main() {
}

res, err = action.Scan(ctx, mc)
if err != nil {
if err != nil && renderer.Name() != "BubbleTeaTerminal" {
returnCode = ExitActionFailed
return fmt.Errorf("scan: %w", err)
}

err = renderer.Full(ctx, res)
if err != nil {
returnCode = ExitRenderFailed
return err
}

if length := func(m *sync.Map) int {
length := func(m *sync.Map) int {
length := 0
m.Range(func(_, _ any) bool {
length++
return true
})
return length
}(&res.Files); length > 0 {
}(&res.Files)

err = renderer.Full(ctx, res)
if err != nil {
returnCode = ExitRenderFailed
return err
}

if length > 0 && mc.Renderer.Name() != "BubbleTeaTerminal" {
fmt.Fprintf(os.Stderr, "\n💡 For detailed analysis, try \"mal analyze <path>\"\n")
}

Expand Down
13 changes: 13 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ require (
github.com/cavaliergopher/cpio v1.0.1
github.com/cavaliergopher/rpm v1.2.0
github.com/chainguard-dev/clog v1.5.1
github.com/charmbracelet/bubbles v0.20.1-0.20241115220041-e5296a2b0fd6
github.com/charmbracelet/bubbletea v1.2.3
github.com/charmbracelet/lipgloss v1.0.0
github.com/egibs/go-debian v0.18.0
github.com/fatih/color v1.18.0
github.com/gabriel-vasile/mimetype v1.4.7
Expand All @@ -24,23 +27,32 @@ require (
)

require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/charmbracelet/x/ansi v0.4.5 // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
github.com/docker/cli v27.3.1+incompatible // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker-credential-helpers v0.8.2 // indirect
github.com/ebitengine/purego v0.8.1 // indirect
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/kr/pretty v0.2.1 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
Expand All @@ -56,5 +68,6 @@ require (
golang.org/x/crypto v0.29.0 // indirect
golang.org/x/net v0.31.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/text v0.20.0 // indirect
pault.ag/go/topsort v0.1.1 // indirect
)
27 changes: 27 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
Expand All @@ -10,6 +12,16 @@ github.com/cavaliergopher/rpm v1.2.0 h1:s0h+QeVK252QFTolkhGiMeQ1f+tMeIMhGl8B1HUm
github.com/cavaliergopher/rpm v1.2.0/go.mod h1:R0q3vTqa7RUvPofAZYrnjJ63hh2vngjFfphuXiExVos=
github.com/chainguard-dev/clog v1.5.1 h1:LeFeVlxiicswuTevtaXc0MXH1zV1iWkbg+H8iUuBTtQ=
github.com/chainguard-dev/clog v1.5.1/go.mod h1:4+WFhRMsGH79etYXY3plYdp+tCz/KCkU8fAr0HoaPvs=
github.com/charmbracelet/bubbles v0.20.1-0.20241115220041-e5296a2b0fd6 h1:GJISC755OMVHyl7Zw9ziGFAXhbwr6FprHjxJYke8lGc=
github.com/charmbracelet/bubbles v0.20.1-0.20241115220041-e5296a2b0fd6/go.mod h1:1WuvnY5+/Kf/JMo0ispmMqILezqZMLBKac+4VANbhfs=
github.com/charmbracelet/bubbletea v1.2.3 h1:d9MdMsANIYZB5pE1KkRqaUV6GfsiWm+/9z4fTuGVm9I=
github.com/charmbracelet/bubbletea v1.2.3/go.mod h1:Qr6fVQw+wX7JkWWkVyXYk/ZUQ92a6XNekLXa3rR18MM=
github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg=
github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo=
github.com/charmbracelet/x/ansi v0.4.5 h1:LqK4vwBNaXw2AyGIICa5/29Sbdq58GbGdFngSexTdRM=
github.com/charmbracelet/x/ansi v0.4.5/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G/ZW/0kEe2oEKCdS/ZxIyoCU=
github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk=
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
Expand All @@ -27,6 +39,8 @@ github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/
github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/egibs/go-debian v0.18.0 h1:NxOTNOJzrjX/hrz+bKcz9TTzyLfuK6u9ytOB6ROZnW4=
github.com/egibs/go-debian v0.18.0/go.mod h1:DRm6WbNRb5VHPAnwpcvSo/0wlnyQnlmJ+5mec1g+qKA=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA=
Expand All @@ -48,6 +62,8 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 h1:7UMa6KCCMjZEMDtTVdcGu0B1GmmC7QJKiCCjyTAWQy0=
github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
Expand All @@ -57,11 +73,19 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
Expand Down Expand Up @@ -111,6 +135,7 @@ golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand All @@ -119,6 +144,8 @@ golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
Expand Down
6 changes: 3 additions & 3 deletions pkg/action/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func scanSinglePath(ctx context.Context, c malcontent.Config, path string, ruleF

mime := "<unknown>"
kind, err := programkind.File(path)
if err != nil {
if err != nil && c.Renderer.Name() != "BubbleTeaTerminal" {
logger.Errorf("file type failure: %s: %s", path, err)
}
if kind != nil {
Expand All @@ -117,7 +117,7 @@ func scanSinglePath(ctx context.Context, c malcontent.Config, path string, ruleF
logger = logger.With("mime", mime)

f, err := os.Open(path)
if err != nil {
if err != nil && c.Renderer.Name() != "BubbleTeaTerminal" {
return nil, err
}
defer f.Close()
Expand Down Expand Up @@ -541,7 +541,7 @@ func processFile(ctx context.Context, c malcontent.Config, ruleFS []fs.FS, path
return nil, nil
}

if fr.Error != "" {
if fr.Error != "" && c.Renderer.Name() != "BubbleTeaTerminal" {
logger.Errorf("scan error: %s", fr.Error)
return nil, fmt.Errorf("report error: %v", fr.Error)
}
Expand Down
1 change: 1 addition & 0 deletions pkg/malcontent/malcontent.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Renderer interface {
Scanning(context.Context, string)
File(context.Context, *FileReport) error
Full(context.Context, *Report) error
Name() string
}

type Config struct {
Expand Down
2 changes: 2 additions & 0 deletions pkg/render/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ func NewJSON(w io.Writer) JSON {
return JSON{w: w}
}

func (r JSON) Name() string { return "JSON" }

func (r JSON) Scanning(_ context.Context, _ string) {}

func (r JSON) File(_ context.Context, _ *malcontent.FileReport) error {
Expand Down
2 changes: 2 additions & 0 deletions pkg/render/markdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ func matchFragmentLink(s string) string {
return fmt.Sprintf("[%s](https://github.com/search?q=%s&type=code)", s, url.QueryEscape(s))
}

func (r Markdown) Name() string { return "Markdown" }

func (r Markdown) Scanning(_ context.Context, _ string) {}

func (r Markdown) File(ctx context.Context, fr *malcontent.FileReport) error {
Expand Down
4 changes: 4 additions & 0 deletions pkg/render/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ func New(kind string, w io.Writer) (malcontent.Renderer, error) {
return NewSimple(w), nil
case "strings":
return NewStringMatches(w), nil
case "interactive":
t := NewInteractive(w)
t.Start()
return t, nil
default:
return nil, fmt.Errorf("unknown renderer: %q", kind)
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/render/simple.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ func NewSimple(w io.Writer) Simple {
return Simple{w: w}
}

func (r Simple) Name() string { return "Simple" }

func (r Simple) Scanning(_ context.Context, _ string) {}

func (r Simple) File(_ context.Context, fr *malcontent.FileReport) error {
Expand Down
2 changes: 2 additions & 0 deletions pkg/render/strings.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ type Match struct {
Strings []string
}

func (r StringMatches) Name() string { return "TerminalStrings" }

func (r StringMatches) Scanning(_ context.Context, path string) {
fmt.Fprintf(r.w, "🔎 Scanning %q\n", path)
}
Expand Down
Loading

0 comments on commit 62ec80f

Please sign in to comment.