Compare commits
10 commits
8d7db7cfa7
...
be41eadb43
Author | SHA1 | Date | |
---|---|---|---|
Lilian Jónsdóttir | be41eadb43 | ||
Lilian Jónsdóttir | b2854a5b98 | ||
Lilian Jónsdóttir | 8b01bffffe | ||
Lilian Jónsdóttir | 0d952302d6 | ||
Lilian Jónsdóttir | 48844886a9 | ||
Lilian Jónsdóttir | 1403f2e62f | ||
Lilian Jónsdóttir | ed2def9c2f | ||
Lilian Jónsdóttir | 3e195f0d73 | ||
Lilian Jónsdóttir | 3f317d58df | ||
Lilian Jónsdóttir | 8e8434bb18 |
24
README.md
24
README.md
|
@ -1,19 +1,29 @@
|
|||
# gt
|
||||
g(o)t(rash) or something like that
|
||||
|
||||
small cli for xdg trash specification
|
||||
g(o)t(rash) is a simple, command line program to interface with the XDG Trash. Files in the trash may be listed, cleaned, or restored via an interactive table, and filtered with various flags.
|
||||
|
||||
## commands
|
||||
## Interactive Mode
|
||||
|
||||
Run with no args to start interactive mode. In interactive mode, files in the trash are displayed, and may be selected to either restore or remove permanently.
|
||||
|
||||
## rm-like Trashing
|
||||
|
||||
Run with no command and only filename(s) as argument(s) to skip displaying files, sending them straight to the trash, in a quick, rm-like way.
|
||||
|
||||
## Commands
|
||||
|
||||
Files are displayed in an interactive table, allowing them to be sorted, filtered, and selectively operated on.
|
||||
|
||||
### trash / tr
|
||||
moves files to trash
|
||||
Find files on the filesystem based on the filter flags and any filename args.
|
||||
|
||||
### list / ls
|
||||
list files in trash
|
||||
Find files in the trash based on the filter flags and any filename args.
|
||||
|
||||
### restore / re
|
||||
restore files from trash
|
||||
Find files in the trash based on the filter flags and any filename args.
|
||||
|
||||
### clean / cl
|
||||
clean files out of trash
|
||||
Find files in the trash based on the filter flags and any filename args.
|
||||
|
||||
See gt(1) or `gt --help` for more in depth information on all command line flags.
|
||||
|
|
13
go.mod
13
go.mod
|
@ -6,12 +6,13 @@ require (
|
|||
github.com/adrg/xdg v0.5.0
|
||||
github.com/charmbracelet/bubbles v0.18.0
|
||||
github.com/charmbracelet/bubbletea v0.26.6
|
||||
github.com/charmbracelet/huh v0.5.1
|
||||
github.com/charmbracelet/huh v0.5.2
|
||||
github.com/charmbracelet/lipgloss v0.12.1
|
||||
github.com/charmbracelet/log v0.4.0
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/ijt/go-anytime v1.9.2
|
||||
github.com/urfave/cli/v2 v2.27.2
|
||||
github.com/lithammer/fuzzysearch v1.1.8
|
||||
github.com/urfave/cli/v2 v2.27.3
|
||||
gitlab.com/tymonx/go-formatter v1.5.1
|
||||
golang.org/x/term v0.22.0
|
||||
gopkg.in/ini.v1 v1.67.0
|
||||
|
@ -22,8 +23,8 @@ require (
|
|||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/catppuccin/go v0.2.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.1.4 // indirect
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240715153702-9ba8adf781c4 // indirect
|
||||
github.com/charmbracelet/x/input v0.1.2 // indirect
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240725160154-f9f6568126ec // indirect
|
||||
github.com/charmbracelet/x/input v0.1.3 // indirect
|
||||
github.com/charmbracelet/x/term v0.1.1 // indirect
|
||||
github.com/charmbracelet/x/windows v0.1.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||
|
@ -33,7 +34,7 @@ require (
|
|||
github.com/lucasb-eyer/go-colorful v1.2.0 // 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.15 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||
|
@ -42,7 +43,7 @@ require (
|
|||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||
golang.org/x/exp v0.0.0-20240716160929-1d5bc16f04a8 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
|
|
55
go.sum
55
go.sum
|
@ -10,20 +10,20 @@ github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/
|
|||
github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw=
|
||||
github.com/charmbracelet/bubbletea v0.26.6 h1:zTCWSuST+3yZYZnVSvbXwKOPRSNZceVeqpzOLN2zq1s=
|
||||
github.com/charmbracelet/bubbletea v0.26.6/go.mod h1:dz8CWPlfCCGLFbBlTY4N7bjLiyOGDJEnd2Muu7pOWhk=
|
||||
github.com/charmbracelet/huh v0.5.1 h1:t5j6g9sMjAE2a9AQuc4lNL7pf/0X4WdHiiMGkL8v/aM=
|
||||
github.com/charmbracelet/huh v0.5.1/go.mod h1:gs7b2brpzXkY0PBWUqJrlzvOowTCL0vNAR6OTItc+kA=
|
||||
github.com/charmbracelet/huh v0.5.2 h1:ofeNkJ4iaFnzv46Njhx896DzLUe/j0L2QAf8znwzX4c=
|
||||
github.com/charmbracelet/huh v0.5.2/go.mod h1:Sf7dY0oAn6N/e3sXJFtFX9hdQLrUdO3z7AYollG9bAM=
|
||||
github.com/charmbracelet/lipgloss v0.12.1 h1:/gmzszl+pedQpjCOH+wFkZr/N90Snz40J/NR7A0zQcs=
|
||||
github.com/charmbracelet/lipgloss v0.12.1/go.mod h1:V2CiwIuhx9S1S1ZlADfOj9HmxeMAORuz5izHb0zGbB8=
|
||||
github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM=
|
||||
github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM=
|
||||
github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM=
|
||||
github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240715153702-9ba8adf781c4 h1:MuGfwxVD0M9WHNVHUBDs4UneZcvcIJyihHlffXcC3FY=
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240715153702-9ba8adf781c4/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ=
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240725160154-f9f6568126ec h1:G79PnmxvVeo5FbAip3VPqAaBkOeXExwvhIBUfrXD5MA=
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240725160154-f9f6568126ec/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ=
|
||||
github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a h1:k/s6UoOSVynWiw7PlclyGO2VdVs5ZLbMIHiGp4shFZE=
|
||||
github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a/go.mod h1:YBotIGhfoWhHDlnUpJMkjebGV2pdGRCn1Y4/Nk/vVcU=
|
||||
github.com/charmbracelet/x/input v0.1.2 h1:QJAZr33eOhDowkkEQ24rsJy4Llxlm+fRDf/cQrmqJa0=
|
||||
github.com/charmbracelet/x/input v0.1.2/go.mod h1:LGBim0maUY4Pitjn/4fHnuXb4KirU3DODsyuHuXdOyA=
|
||||
github.com/charmbracelet/x/input v0.1.3 h1:oy4TMhyGQsYs/WWJwu1ELUMFnjiUAXwtDf048fHbCkg=
|
||||
github.com/charmbracelet/x/input v0.1.3/go.mod h1:1gaCOyw1KI9e2j00j/BBZ4ErzRZqa05w0Ghn83yIhKU=
|
||||
github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI=
|
||||
github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw=
|
||||
github.com/charmbracelet/x/windows v0.1.2 h1:Iumiwq2G+BRmgoayww/qfcvof7W/3uLoelhxojXlRWg=
|
||||
|
@ -45,6 +45,8 @@ github.com/ijt/go-anytime v1.9.2 h1:DmYgVwUiFPNR+n6c1T5P070tlGATRZG4aYNJs6XDUfU=
|
|||
github.com/ijt/go-anytime v1.9.2/go.mod h1:egBT6FhVjNlXNHUN2wTPi6ILCNKXeeXFy04pWJjw/LI=
|
||||
github.com/ijt/goparsify v0.0.0-20221203142333-3a5276334b8d h1:LFOmpWrSbtolg0YqYC9hQjj5WSLtRGb6aZ3JAugLfgg=
|
||||
github.com/ijt/goparsify v0.0.0-20221203142333-3a5276334b8d/go.mod h1:112TOyA+aruNSUBlyBWlKBdLVYTdhjiO2CKD0j/URSU=
|
||||
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
|
||||
github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
|
||||
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/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
|
@ -52,8 +54,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
|||
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.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
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/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
||||
|
@ -75,35 +77,60 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
|
|||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tj/assert v0.0.0-20190920132354-ee03d75cd160 h1:NSWpaDaurcAJY7PkL8Xt0PhZE7qpvbZl5ljd8r6U0bI=
|
||||
github.com/tj/assert v0.0.0-20190920132354-ee03d75cd160/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
|
||||
github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI=
|
||||
github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM=
|
||||
github.com/urfave/cli/v2 v2.27.3 h1:/POWahRmdh7uztQ3CYnaDddk0Rm90PyOgIxgW2rr41M=
|
||||
github.com/urfave/cli/v2 v2.27.3/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
gitlab.com/tymonx/go-formatter v1.5.1 h1:gmn5rJqR6LlI1DkpBmiCo0MZ3ges581A14GZcXlGe60=
|
||||
gitlab.com/tymonx/go-formatter v1.5.1/go.mod h1:z1E064wx+cgg5ChY+1E+hrJf8uKY//kF1Q1As+w5WRQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w=
|
||||
golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/exp v0.0.0-20240716160929-1d5bc16f04a8 h1:Z+vTUQyBb738QmIhbJx3z4htsxDeI+rd0EHvNm8jHkg=
|
||||
golang.org/x/exp v0.0.0-20240716160929-1d5bc16f04a8/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
||||
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
|
|
238
gt.1
Normal file
238
gt.1
Normal file
|
@ -0,0 +1,238 @@
|
|||
.\" Generated by scdoc 1.11.3
|
||||
.\" Complete documentation for this program is not available as a GNU info page
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.nh
|
||||
.ad l
|
||||
.\" Begin generated content:
|
||||
.TH "gt" "1" "2024-07-31" "gt version v0.0.1" "User Commands"
|
||||
.PP
|
||||
.SH NAME
|
||||
.PP
|
||||
gt - manual page for gt version 0.\&0.\&1
|
||||
.PP
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
.SS NAME:
|
||||
.PP
|
||||
gt - Simple command line XDG Trash application
|
||||
.PP
|
||||
.SS USAGE:
|
||||
.PP
|
||||
gt [global options] [command [command options] / filename(s)]
|
||||
.PP
|
||||
.SS INFO:
|
||||
.PP
|
||||
g(o)t(rash) is a simple, command line program to interface with the XDG Trash.\& Files in the trash may be listed, cleaned, or restored via an interactive table, and filtered with various flags.\&
|
||||
.PP
|
||||
.SS VERSION:
|
||||
.PP
|
||||
0.\&0.\&1
|
||||
.PP
|
||||
.SS AUTHOR:
|
||||
.PP
|
||||
Lilian Jónsdóttir <lilian.\&jonsdottir@gmail.\&com>
|
||||
.PP
|
||||
.SH INTERACTIVE MODE
|
||||
.PP
|
||||
Run with no args to start interactive mode.\& In interactive mode, files in the trash are displayed, and may be selected to either restore or remove permanently.\&
|
||||
.PP
|
||||
.SH RM-LIKE TRASHING
|
||||
.PP
|
||||
Run with no command and only filename(s) as argument(s) to skip displaying files, sending them straight to the trash, in a quick, rm-like way.\&
|
||||
.PP
|
||||
.SH COMMANDS
|
||||
.PP
|
||||
.SS TRASH:
|
||||
\fIcommand\fR: trash, tr
|
||||
.RS 4
|
||||
Trash a file or files
|
||||
.PP
|
||||
.RE
|
||||
\fIusage\fR:
|
||||
.RS 4
|
||||
trash [command options] [filename(s)]
|
||||
.PP
|
||||
.RE
|
||||
\fIinfo\fR:
|
||||
.RS 4
|
||||
The trash command finds files on the filesystem based on the filter flags and any filename args, and displays them in an interactive table, allowing them to be sorted, filtered, and selectively trashed.\&
|
||||
.PP
|
||||
.RE
|
||||
\fIflags\fR:
|
||||
.RS 4
|
||||
\fB--recursive\fR, \fB-r\fR
|
||||
.RS 4
|
||||
operate on files recursively
|
||||
.PP
|
||||
.RE
|
||||
\fB--work-dir\fR dir, \fB-w\fR dir
|
||||
.RS 4
|
||||
operate on files in this `DIRECTORY`
|
||||
.PP
|
||||
.RE
|
||||
\fB--hidden\fR, \fB-h\fR
|
||||
.RS 4
|
||||
operate on hidden files
|
||||
.PP
|
||||
.RE
|
||||
.RE
|
||||
.SS LIST:
|
||||
\fIcommand\fR: list, ls
|
||||
.RS 4
|
||||
List trashed files
|
||||
.PP
|
||||
.RE
|
||||
\fIusage\fR:
|
||||
.RS 4
|
||||
list [command options] [filename(s)]
|
||||
.PP
|
||||
.RE
|
||||
\fIinfo\fR:
|
||||
.RS 4
|
||||
The list command finds files in the trash based on the filter flags and any filename args, and displays them in an interactive table, allowing them to be sorted, filtered.\&
|
||||
.PP
|
||||
.RE
|
||||
\fIflags:\fR
|
||||
.RS 4
|
||||
\fB--non-interactive\fR, \fB-n\fR
|
||||
.RS 4
|
||||
list files and quit
|
||||
.PP
|
||||
.RE
|
||||
\fB--original-path\fR dir, \fB-O\fR dir
|
||||
.RS 4
|
||||
list files trashed from this directory
|
||||
.PP
|
||||
.RE
|
||||
.RE
|
||||
.SS RESTORE:
|
||||
\fIcommand\fR: restore, re
|
||||
.RS 4
|
||||
Restore a trashed file or files
|
||||
.PP
|
||||
.RE
|
||||
\fIusage\fR:
|
||||
.RS 4
|
||||
restore [command options] [filename(s)]
|
||||
.PP
|
||||
.RE
|
||||
\fIinfo\fR:
|
||||
.RS 4
|
||||
The restore command finds files in the trash based on the filter flags and any filename args, and displays them in an interactive table, allowing them to be sorted, filtered, and selectively restored.\&
|
||||
.PP
|
||||
.RE
|
||||
\fIflags:\fR
|
||||
.RS 4
|
||||
\fB--all\fR, \fB-a\fR
|
||||
.RS 4
|
||||
operate on all files in trash
|
||||
.PP
|
||||
.RE
|
||||
\fB--original-path\fR dir, \fB-O\fR dir
|
||||
.RS 4
|
||||
restore files trashed from this directory
|
||||
.PP
|
||||
.RE
|
||||
.RE
|
||||
.SS CLEAN:
|
||||
\fIcommand\fR: clean, cl
|
||||
.RS 4
|
||||
Clean files from trash
|
||||
.PP
|
||||
.RE
|
||||
\fIusage\fR:
|
||||
.RS 4
|
||||
clean [command options] [filename(s)]
|
||||
.PP
|
||||
.RE
|
||||
\fIinfo\fR:
|
||||
.RS 4
|
||||
The clean command finds files in the trash based on the filter flags and any filename args, and displays them in an interactive table, allowing them to be sorted, filtered, and selectively removed permanently.\&
|
||||
.PP
|
||||
.RE
|
||||
\fIflags:\fR
|
||||
.RS 4
|
||||
\fB--all\fR, \fB-a\fR
|
||||
.RS 4
|
||||
operate on all files in trash
|
||||
.PP
|
||||
.RE
|
||||
\fB--original-path\fR dir, \fB-O\fR dir
|
||||
.RS 4
|
||||
remove files trashed from this directory
|
||||
.PP
|
||||
.RE
|
||||
.RE
|
||||
.SH GLOBAL FLAGS
|
||||
.PP
|
||||
\fB--confirm\fR, \fB-c\fR
|
||||
.RS 4
|
||||
ask for confirmation before executing any action
|
||||
.PP
|
||||
.RE
|
||||
\fB--log\fR level, \fB-l\fR level
|
||||
.RS 4
|
||||
set log level
|
||||
.PP
|
||||
.RE
|
||||
.SH FILTER FLAGS (USABLE WITH ALL COMMANDS)
|
||||
.PP
|
||||
\fB--match\fR pattern, \fB-m\fR pattern
|
||||
.RS 4
|
||||
operate on files matching regex pattern
|
||||
.PP
|
||||
.RE
|
||||
\fB--glob\fR pattern, \fB-m\fR pattern
|
||||
.RS 4
|
||||
operate on files matching glob
|
||||
.PP
|
||||
.RE
|
||||
\fB--not-match\fR pattern, \fB-M\fR pattern
|
||||
.RS 4
|
||||
operate on files not matching regex pattern
|
||||
.PP
|
||||
.RE
|
||||
\fB--not-glob\fR pattern, \fB-G\fR pattern
|
||||
.RS 4
|
||||
operate on files not matching glob
|
||||
.PP
|
||||
.RE
|
||||
\fB--on\fR date, \fB-O\fR date
|
||||
.RS 4
|
||||
operate on files modified on date
|
||||
.PP
|
||||
.RE
|
||||
\fB--before\fR date, \fB-B\fR date
|
||||
.RS 4
|
||||
operate on files modified before date
|
||||
.PP
|
||||
.RE
|
||||
\fB--after\fR date, \fB-A\fR date
|
||||
.RS 4
|
||||
operate on files modified after date
|
||||
.PP
|
||||
.RE
|
||||
\fB--files-only\fR, \fB-F\fR
|
||||
.RS 4
|
||||
operate on files only
|
||||
.PP
|
||||
.RE
|
||||
\fB--dirs-only\fR, \fB-D\fR
|
||||
.RS 4
|
||||
operate on directories only
|
||||
.PP
|
||||
.RE
|
||||
\fB--min-size\fR size, \fB-N\fR size
|
||||
.RS 4
|
||||
operate on files larger than size
|
||||
.PP
|
||||
.RE
|
||||
\fB--max-size\fR size, \fB-X\fR size
|
||||
.RS 4
|
||||
operate on files smaller than size
|
||||
.PP
|
||||
.RE
|
||||
\fB--mode\fR mode, \fB-x\fR mode
|
||||
.RS 4
|
||||
operate on files matching mode mode
|
154
gt.1.scd
Normal file
154
gt.1.scd
Normal file
|
@ -0,0 +1,154 @@
|
|||
gt(1) ["gt version v0.0.1" ["User Commands"]]
|
||||
|
||||
# NAME
|
||||
|
||||
gt \- manual page for gt version 0.0.1
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
## NAME:
|
||||
|
||||
gt \- Simple command line XDG Trash application
|
||||
|
||||
## USAGE:
|
||||
|
||||
gt [global options] [command [command options] / filename(s)]
|
||||
|
||||
## INFO:
|
||||
|
||||
g(o)t(rash) is a simple, command line program to interface with the XDG Trash. Files in the trash may be listed, cleaned, or restored via an interactive table, and filtered with various flags.
|
||||
|
||||
## VERSION:
|
||||
|
||||
0.0.1
|
||||
|
||||
## AUTHOR:
|
||||
|
||||
Lilian Jónsdóttir <lilian.jonsdottir@gmail.com>
|
||||
|
||||
# INTERACTIVE MODE
|
||||
|
||||
Run with no args to start interactive mode. In interactive mode, files in the trash are displayed, and may be selected to either restore or remove permanently.
|
||||
|
||||
# RM-LIKE TRASHING
|
||||
|
||||
Run with no command and only filename(s) as argument(s) to skip displaying files, sending them straight to the trash, in a quick, rm-like way.
|
||||
|
||||
# COMMANDS
|
||||
|
||||
## TRASH:
|
||||
_command_: trash, tr
|
||||
Trash a file or files
|
||||
|
||||
_usage_:
|
||||
trash [command options] [filename(s)]
|
||||
|
||||
_info_:
|
||||
The trash command finds files on the filesystem based on the filter flags and any filename args, and displays them in an interactive table, allowing them to be sorted, filtered, and selectively trashed.
|
||||
|
||||
_flags_:
|
||||
*--recursive*, *-r*
|
||||
operate on files recursively
|
||||
|
||||
*--work-dir* dir, *-w* dir
|
||||
operate on files in this `DIRECTORY`
|
||||
|
||||
*--hidden*, *-h*
|
||||
operate on hidden files
|
||||
|
||||
## LIST:
|
||||
_command_: list, ls
|
||||
List trashed files
|
||||
|
||||
_usage_:
|
||||
list [command options] [filename(s)]
|
||||
|
||||
_info_:
|
||||
The list command finds files in the trash based on the filter flags and any filename args, and displays them in an interactive table, allowing them to be sorted, filtered.
|
||||
|
||||
_flags:_
|
||||
*--non-interactive*, *-n*
|
||||
list files and quit
|
||||
|
||||
*--original-path* dir, *-O* dir
|
||||
list files trashed from this directory
|
||||
|
||||
## RESTORE:
|
||||
_command_: restore, re
|
||||
Restore a trashed file or files
|
||||
|
||||
_usage_:
|
||||
restore [command options] [filename(s)]
|
||||
|
||||
_info_:
|
||||
The restore command finds files in the trash based on the filter flags and any filename args, and displays them in an interactive table, allowing them to be sorted, filtered, and selectively restored.
|
||||
|
||||
_flags:_
|
||||
*--all*, *-a*
|
||||
operate on all files in trash
|
||||
|
||||
*--original-path* dir, *-O* dir
|
||||
restore files trashed from this directory
|
||||
|
||||
## CLEAN:
|
||||
_command_: clean, cl
|
||||
Clean files from trash
|
||||
|
||||
_usage_:
|
||||
clean [command options] [filename(s)]
|
||||
|
||||
_info_:
|
||||
The clean command finds files in the trash based on the filter flags and any filename args, and displays them in an interactive table, allowing them to be sorted, filtered, and selectively removed permanently.
|
||||
|
||||
_flags:_
|
||||
*--all*, *-a*
|
||||
operate on all files in trash
|
||||
|
||||
*--original-path* dir, *-O* dir
|
||||
remove files trashed from this directory
|
||||
|
||||
# GLOBAL FLAGS
|
||||
|
||||
*--confirm*, *-c*
|
||||
ask for confirmation before executing any action
|
||||
|
||||
*--log* level, *-l* level
|
||||
set log level
|
||||
|
||||
# FILTER FLAGS (USABLE WITH ALL COMMANDS)
|
||||
|
||||
*--match* pattern, *-m* pattern
|
||||
operate on files matching regex pattern
|
||||
|
||||
*--glob* pattern, *-m* pattern
|
||||
operate on files matching glob
|
||||
|
||||
*--not-match* pattern, *-M* pattern
|
||||
operate on files not matching regex pattern
|
||||
|
||||
*--not-glob* pattern, *-G* pattern
|
||||
operate on files not matching glob
|
||||
|
||||
*--on* date, *-O* date
|
||||
operate on files modified on date
|
||||
|
||||
*--before* date, *-B* date
|
||||
operate on files modified before date
|
||||
|
||||
*--after* date, *-A* date
|
||||
operate on files modified after date
|
||||
|
||||
*--files-only*, *-F*
|
||||
operate on files only
|
||||
|
||||
*--dirs-only*, *-D*
|
||||
operate on directories only
|
||||
|
||||
*--min-size* size, *-N* size
|
||||
operate on files larger than size
|
||||
|
||||
*--max-size* size, *-X* size
|
||||
operate on files smaller than size
|
||||
|
||||
*--mode* mode, *-x* mode
|
||||
operate on files matching mode mode
|
|
@ -18,6 +18,7 @@ import (
|
|||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/lithammer/fuzzysearch/fuzzy"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -28,12 +29,19 @@ const (
|
|||
hoffset int = 6
|
||||
poffset int = 2
|
||||
|
||||
filenameColumn string = "filename"
|
||||
pathColumn string = "path"
|
||||
modifiedColumn string = "modified"
|
||||
trashedColumn string = "trashed"
|
||||
sizeColumn string = "size"
|
||||
bar string = "───"
|
||||
|
||||
// TODO: figure these out dynamically based on longest of each
|
||||
filenameColumn float64 = 0.46
|
||||
pathColumn float64 = 0.25
|
||||
dateColumn float64 = 0.15
|
||||
sizeColumn float64 = 0.12
|
||||
checkColumn float64 = 0.02
|
||||
filenameColumnW float64 = 0.46
|
||||
pathColumnW float64 = 0.25
|
||||
dateColumnW float64 = 0.15
|
||||
sizeColumnW float64 = 0.12
|
||||
checkColumnW float64 = 0.02
|
||||
|
||||
// TODO: make these configurable or something
|
||||
borderbg string = "5"
|
||||
|
@ -65,21 +73,24 @@ type model struct {
|
|||
selectsize int64
|
||||
readonly bool
|
||||
once bool
|
||||
filtering bool
|
||||
filter string
|
||||
termheight int
|
||||
termwidth int
|
||||
mode modes.Mode
|
||||
sorting sorting.Sorting
|
||||
workdir string
|
||||
files files.Files
|
||||
fltrfiles files.Files
|
||||
}
|
||||
|
||||
func newModel(fls []files.File, width, height int, readonly, once bool, workdir string, mode modes.Mode) model {
|
||||
func newModel(fls []files.File, width, height int, selectall, readonly, once bool, workdir string, mode modes.Mode) model {
|
||||
var (
|
||||
fwidth = int(math.Round(float64(width-woffset) * filenameColumn))
|
||||
owidth = int(math.Round(float64(width-woffset) * pathColumn))
|
||||
dwidth = int(math.Round(float64(width-woffset) * dateColumn))
|
||||
swidth = int(math.Round(float64(width-woffset) * sizeColumn))
|
||||
cwidth = int(math.Round(float64(width-woffset) * checkColumn))
|
||||
fwidth = int(math.Round(float64(width-woffset) * filenameColumnW))
|
||||
owidth = int(math.Round(float64(width-woffset) * pathColumnW))
|
||||
dwidth = int(math.Round(float64(width-woffset) * dateColumnW))
|
||||
swidth = int(math.Round(float64(width-woffset) * sizeColumnW))
|
||||
cwidth = int(math.Round(float64(width-woffset) * checkColumnW))
|
||||
theight = min(height-hoffset, len(fls))
|
||||
|
||||
mdl = model{
|
||||
|
@ -104,16 +115,16 @@ func newModel(fls []files.File, width, height int, readonly, once bool, workdir
|
|||
var datecolumn string
|
||||
switch mdl.mode {
|
||||
case modes.Trashing:
|
||||
datecolumn = "modified"
|
||||
datecolumn = modifiedColumn
|
||||
default:
|
||||
datecolumn = "trashed"
|
||||
datecolumn = trashedColumn
|
||||
}
|
||||
|
||||
columns := []table.Column{
|
||||
{Title: "filename", Width: fwidth},
|
||||
{Title: "path", Width: owidth},
|
||||
{Title: filenameColumn, Width: fwidth},
|
||||
{Title: pathColumn, Width: owidth},
|
||||
{Title: datecolumn, Width: dwidth},
|
||||
{Title: "size", Width: swidth},
|
||||
{Title: sizeColumn, Width: swidth},
|
||||
}
|
||||
if !mdl.readonly {
|
||||
columns = append(columns, table.Column{Title: uncheck, Width: cwidth})
|
||||
|
@ -126,6 +137,10 @@ func newModel(fls []files.File, width, height int, readonly, once bool, workdir
|
|||
mdl.sorting = sorting.Name
|
||||
mdl.sort()
|
||||
|
||||
if selectall {
|
||||
mdl.selectAll()
|
||||
}
|
||||
|
||||
return mdl
|
||||
}
|
||||
|
||||
|
@ -139,6 +154,10 @@ type keyMap struct {
|
|||
clen key.Binding
|
||||
sort key.Binding
|
||||
rort key.Binding
|
||||
fltr key.Binding
|
||||
clfl key.Binding
|
||||
apfl key.Binding
|
||||
bksp key.Binding
|
||||
quit key.Binding
|
||||
}
|
||||
|
||||
|
@ -180,6 +199,22 @@ func defaultKeyMap() keyMap {
|
|||
key.WithKeys("S"),
|
||||
key.WithHelp("S", "sort (reverse)"),
|
||||
),
|
||||
fltr: key.NewBinding(
|
||||
key.WithKeys("/"),
|
||||
key.WithHelp("/", "filter"),
|
||||
),
|
||||
apfl: key.NewBinding(
|
||||
key.WithKeys("enter"),
|
||||
key.WithHelp("enter", "apply filter"),
|
||||
),
|
||||
clfl: key.NewBinding(
|
||||
key.WithKeys("esc"),
|
||||
key.WithHelp("esc", "clear filter"),
|
||||
),
|
||||
bksp: key.NewBinding(
|
||||
key.WithKeys("backspace"),
|
||||
key.WithHelp("backspace", "backspace"),
|
||||
),
|
||||
quit: key.NewBinding(
|
||||
key.WithKeys("q", "ctrl+c"),
|
||||
key.WithHelp("q", "quit"),
|
||||
|
@ -205,11 +240,29 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
if m.filtering {
|
||||
switch {
|
||||
case key.Matches(msg, m.keys.clfl):
|
||||
m.filter = ""
|
||||
m.filtering = false
|
||||
case key.Matches(msg, m.keys.apfl):
|
||||
m.filtering = false
|
||||
case key.Matches(msg, m.keys.bksp):
|
||||
if len(m.filter) > 0 {
|
||||
m.filter = m.filter[:len(m.filter)-1]
|
||||
}
|
||||
default:
|
||||
m.filter += msg.String()
|
||||
}
|
||||
m.applyFilter()
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
switch {
|
||||
case key.Matches(msg, m.keys.mark):
|
||||
m.toggleItem(m.table.Cursor())
|
||||
case key.Matches(msg, m.keys.doit):
|
||||
if !m.readonly && m.mode != modes.Interactive {
|
||||
if !m.readonly && m.mode != modes.Interactive && len(m.fltrfiles) > 1 {
|
||||
return m.quit(false)
|
||||
}
|
||||
case key.Matches(msg, m.keys.nada):
|
||||
|
@ -228,6 +281,13 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
case key.Matches(msg, m.keys.rort):
|
||||
m.sorting = m.sorting.Prev()
|
||||
m.sort()
|
||||
case key.Matches(msg, m.keys.fltr):
|
||||
m.filtering = true
|
||||
case key.Matches(msg, m.keys.clfl):
|
||||
if m.filter != "" {
|
||||
m.filter = ""
|
||||
m.applyFilter()
|
||||
}
|
||||
case key.Matches(msg, m.keys.quit):
|
||||
return m.quit(true)
|
||||
}
|
||||
|
@ -240,46 +300,60 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
|
||||
func (m model) View() string {
|
||||
var panels []string
|
||||
|
||||
if m.mode != modes.Listing {
|
||||
if !m.once {
|
||||
panels = append(panels, m.header())
|
||||
}
|
||||
|
||||
panels = append(panels, style.Render(m.table.View()), m.footer())
|
||||
|
||||
return lipgloss.JoinVertical(lipgloss.Top, panels...)
|
||||
return lipgloss.JoinVertical(lipgloss.Top,
|
||||
panels...,
|
||||
)
|
||||
}
|
||||
|
||||
func (m model) showHelp() string {
|
||||
// TODO: maybe use bubbletea built in help
|
||||
var keys = []string{
|
||||
fmt.Sprintf("%s %s (%s)", darktext.Render(m.keys.sort.Help().Key), darkertext.Render(m.keys.sort.Help().Desc), m.sorting.String()),
|
||||
fmt.Sprintf("%s %s", darktext.Render(m.keys.quit.Help().Key), darkertext.Render(m.keys.quit.Help().Desc)),
|
||||
var filterText string
|
||||
if m.filter != "" {
|
||||
filterText = fmt.Sprintf(" (%s)", m.filter)
|
||||
}
|
||||
|
||||
keys := []string{
|
||||
fmt.Sprintf("%s %s%s", darktext.Render(m.keys.fltr.Help().Key), darkertext.Render(m.keys.fltr.Help().Desc), filterText),
|
||||
fmt.Sprintf("%s %s (%s)", darktext.Render(m.keys.sort.Help().Key), darkertext.Render(m.keys.sort.Help().Desc), m.sorting.String()),
|
||||
styleKey(m.keys.quit),
|
||||
}
|
||||
|
||||
if !m.readonly {
|
||||
if m.mode != modes.Interactive {
|
||||
keys = append([]string{
|
||||
fmt.Sprintf("%s %s", darktext.Render(m.keys.doit.Help().Key), darkertext.Render(m.keys.doit.Help().Desc)),
|
||||
styleKey(m.keys.doit),
|
||||
}, keys...)
|
||||
}
|
||||
keys = append([]string{
|
||||
fmt.Sprintf("%s %s", darktext.Render(m.keys.mark.Help().Key), darkertext.Render(m.keys.mark.Help().Desc)),
|
||||
styleKey(m.keys.mark),
|
||||
}, keys...)
|
||||
}
|
||||
return strings.Join(keys, darkesttext.Render(" • "))
|
||||
}
|
||||
|
||||
func (m model) header() string {
|
||||
// TODO: clean this ugly thing up
|
||||
var (
|
||||
right, left string
|
||||
spacerWidth int
|
||||
keys = []string{
|
||||
fmt.Sprintf("%s %s", darktext.Render(m.keys.rstr.Help().Key), darkertext.Render(m.keys.rstr.Help().Desc)),
|
||||
fmt.Sprintf("%s %s", darktext.Render(m.keys.clen.Help().Key), darkertext.Render(m.keys.clen.Help().Desc)),
|
||||
styleKey(m.keys.rstr),
|
||||
styleKey(m.keys.clen),
|
||||
}
|
||||
selectKeys = []string{
|
||||
fmt.Sprintf("%s %s", darktext.Render(m.keys.todo.Help().Key), darkertext.Render(m.keys.todo.Help().Desc)),
|
||||
fmt.Sprintf("%s %s", darktext.Render(m.keys.nada.Help().Key), darkertext.Render(m.keys.nada.Help().Desc)),
|
||||
fmt.Sprintf("%s %s", darktext.Render(m.keys.invr.Help().Key), darkertext.Render(m.keys.invr.Help().Desc)),
|
||||
styleKey(m.keys.todo),
|
||||
styleKey(m.keys.nada),
|
||||
styleKey(m.keys.invr),
|
||||
}
|
||||
filterKeys = []string{
|
||||
styleKey(m.keys.clfl),
|
||||
styleKey(m.keys.apfl),
|
||||
}
|
||||
dot = darkesttext.Render("•")
|
||||
wideDot = darkesttext.Render(" • ")
|
||||
|
@ -297,7 +371,20 @@ func (m model) header() string {
|
|||
}
|
||||
right += fmt.Sprintf(" %s %s", dot, strings.Join(selectKeys, wideDot))
|
||||
|
||||
left = fmt.Sprintf("%d/%d %s %s", len(m.selected), len(m.table.Rows()), dot, humanize.Bytes(uint64(m.selectsize)))
|
||||
left = fmt.Sprintf("%d/%d %s %s", len(m.selected), len(m.fltrfiles), dot, humanize.Bytes(uint64(m.selectsize)))
|
||||
|
||||
if m.mode == modes.Listing {
|
||||
title := "Showing"
|
||||
if m.filter != "" || m.filtering {
|
||||
title += " (filtered)"
|
||||
}
|
||||
right = fmt.Sprintf(" %s %d files in trash", title, len(m.fltrfiles))
|
||||
left = ""
|
||||
}
|
||||
|
||||
if m.filtering {
|
||||
right = fmt.Sprintf(" Filtering %s %s", dot, strings.Join(filterKeys, wideDot))
|
||||
}
|
||||
|
||||
// offset of 2 again because of table border
|
||||
spacerWidth = m.termwidth - lipgloss.Width(right) - lipgloss.Width(left) - poffset
|
||||
|
@ -323,7 +410,7 @@ func (m model) quit(unselectAll bool) (model, tea.Cmd) {
|
|||
}
|
||||
|
||||
func (m model) execute(mode modes.Mode) (model, tea.Cmd) {
|
||||
if m.mode != modes.Interactive || len(m.selected) <= 0 {
|
||||
if m.mode != modes.Interactive || len(m.selected) <= 0 || len(m.fltrfiles) <= 0 {
|
||||
var cmd tea.Cmd
|
||||
return m, cmd
|
||||
}
|
||||
|
@ -335,7 +422,7 @@ func (m model) execute(mode modes.Mode) (model, tea.Cmd) {
|
|||
}
|
||||
|
||||
func (m model) selectedFiles() (outfile files.Files) {
|
||||
for _, file := range m.files {
|
||||
for _, file := range m.fltrfiles {
|
||||
if m.selected[file.String()] {
|
||||
outfile = append(outfile, file)
|
||||
}
|
||||
|
@ -408,12 +495,12 @@ func (m *model) updateRows(selected bool) {
|
|||
}
|
||||
|
||||
func (m *model) toggleItem(index int) (selected bool) {
|
||||
if m.readonly {
|
||||
if m.readonly || len(m.fltrfiles) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
name := m.files[index].String()
|
||||
size := m.files[index].Filesize()
|
||||
name := m.fltrfiles[index].String()
|
||||
size := m.fltrfiles[index].Filesize()
|
||||
|
||||
// select the thing
|
||||
if v, ok := m.selected[name]; v && ok {
|
||||
|
@ -434,15 +521,15 @@ func (m *model) toggleItem(index int) (selected bool) {
|
|||
}
|
||||
|
||||
func (m *model) selectAll() {
|
||||
if m.readonly {
|
||||
if m.readonly || len(m.fltrfiles) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
m.selected = map[string]bool{}
|
||||
m.selectsize = 0
|
||||
for i := range m.table.Rows() {
|
||||
m.selected[m.files[i].String()] = true
|
||||
m.selectsize += m.files[i].Filesize()
|
||||
m.selected[m.fltrfiles[i].String()] = true
|
||||
m.selectsize += m.fltrfiles[i].Filesize()
|
||||
}
|
||||
m.updateRows(true)
|
||||
}
|
||||
|
@ -458,15 +545,15 @@ func (m *model) unselectAll() {
|
|||
}
|
||||
|
||||
func (m *model) invertSelection() {
|
||||
if m.readonly {
|
||||
if m.readonly || len(m.fltrfiles) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var newrows []table.Row
|
||||
|
||||
for index, row := range m.table.Rows() {
|
||||
name := m.files[index].String()
|
||||
size := m.files[index].Filesize()
|
||||
name := m.fltrfiles[index].String()
|
||||
size := m.fltrfiles[index].Filesize()
|
||||
if v, ok := m.selected[name]; v && ok {
|
||||
delete(m.selected, name)
|
||||
m.selectsize -= size
|
||||
|
@ -495,20 +582,55 @@ func (m *model) invertSelection() {
|
|||
|
||||
func (m *model) sort() {
|
||||
slices.SortStableFunc(m.files, m.sorting.Sorter())
|
||||
var rows = []table.Row{}
|
||||
for _, file := range m.files {
|
||||
r := newRow(file, m.workdir)
|
||||
if !m.readonly {
|
||||
r = append(r, getCheck(m.selected[file.String()]))
|
||||
}
|
||||
rows = append(rows, r)
|
||||
}
|
||||
|
||||
m.table.SetRows(rows)
|
||||
m.applyFilter()
|
||||
}
|
||||
|
||||
func Select(fls files.Files, width, height int, readonly, once bool, workdir string, mode modes.Mode) (files.Files, modes.Mode, error) {
|
||||
mdl := newModel(fls, width, height, readonly, once, workdir, mode)
|
||||
func (m *model) applyFilter() {
|
||||
m.fltrfiles = m.filteredFiles()
|
||||
var rows = []table.Row{}
|
||||
for _, file := range m.fltrfiles {
|
||||
row := newRow(file, m.workdir)
|
||||
if !m.readonly {
|
||||
row = append(row, getCheck(m.selected[file.String()]))
|
||||
}
|
||||
rows = append(rows, row)
|
||||
}
|
||||
|
||||
if len(rows) < 1 {
|
||||
row := table.Row{"no files matched filter!", bar, bar, bar}
|
||||
if !m.readonly {
|
||||
row = append(row, uncheck)
|
||||
}
|
||||
rows = append(rows, row)
|
||||
}
|
||||
m.table.SetRows(rows)
|
||||
m.updateTableHeight()
|
||||
}
|
||||
|
||||
func (m *model) filteredFiles() (filteredFiles files.Files) {
|
||||
for _, file := range m.files {
|
||||
if isMatch(m.filter, file.Name()) {
|
||||
filteredFiles = append(filteredFiles, file)
|
||||
} else {
|
||||
if _, ok := m.selected[file.String()]; ok {
|
||||
delete(m.selected, file.String())
|
||||
m.selectsize -= file.Filesize()
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (m *model) updateTableHeight() {
|
||||
h := min(m.termheight-hoffset, len(m.table.Rows()))
|
||||
m.table.SetHeight(h)
|
||||
if m.table.Cursor() >= h {
|
||||
m.table.SetCursor(h - 1)
|
||||
}
|
||||
}
|
||||
|
||||
func Select(fls files.Files, width, height int, selectall, once bool, workdir string, mode modes.Mode) (files.Files, modes.Mode, error) {
|
||||
mdl := newModel(fls, width, height, selectall, false, once, workdir, mode)
|
||||
endmodel, err := tea.NewProgram(mdl).Run()
|
||||
if err != nil {
|
||||
return fls, 0, err
|
||||
|
@ -520,19 +642,27 @@ func Select(fls files.Files, width, height int, readonly, once bool, workdir str
|
|||
return m.selectedFiles(), m.mode, nil
|
||||
}
|
||||
|
||||
func Show(fls files.Files, width, height int, once bool, workdir string) error {
|
||||
mdl := newModel(fls, width, height, false, true, once, workdir, modes.Listing)
|
||||
if _, err := tea.NewProgram(mdl).Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newRow(file files.File, workdir string) table.Row {
|
||||
var time, bar string
|
||||
var time, size string
|
||||
time = humanize.Time(file.Date())
|
||||
if file.IsDir() {
|
||||
bar = strings.Repeat("─", poffset+1)
|
||||
size = bar
|
||||
} else {
|
||||
bar = humanize.Bytes(uint64(file.Filesize()))
|
||||
size = humanize.Bytes(uint64(file.Filesize()))
|
||||
}
|
||||
return table.Row{
|
||||
dirs.UnEscape(file.Name()),
|
||||
dirs.UnExpand(filepath.Dir(file.Path()), workdir),
|
||||
time,
|
||||
bar,
|
||||
size,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -593,3 +723,13 @@ func makeUnselectedStyle() table.Styles {
|
|||
Bold(false)
|
||||
return style
|
||||
}
|
||||
|
||||
func styleKey(key key.Binding) string {
|
||||
return fmt.Sprintf("%s %s", darktext.Render(key.Help().Key), darkertext.Render(key.Help().Desc))
|
||||
}
|
||||
|
||||
func isMatch(pattern, filename string) bool {
|
||||
p := strings.ToLower(pattern)
|
||||
f := strings.ToLower(filename)
|
||||
return fuzzy.Match(p, f)
|
||||
}
|
||||
|
|
9
justfile
9
justfile
|
@ -30,6 +30,11 @@ run-args args:
|
|||
install:
|
||||
go install {{cmd}}
|
||||
|
||||
# install manpages into $HOME/.local/share/man
|
||||
install-man:
|
||||
mkdir -p $HOME/.local/share/man/man1
|
||||
cp {{binary}}.1 $HOME/.local/share/man/man1/{{binary}}.1
|
||||
|
||||
# clean up after yourself
|
||||
clean:
|
||||
rm {{output}}
|
||||
|
@ -41,3 +46,7 @@ test:
|
|||
# run linter
|
||||
check:
|
||||
staticcheck ./...
|
||||
|
||||
# generate manpage
|
||||
man:
|
||||
scdoc < {{binary}}.1.scd > {{binary}}.1
|
||||
|
|
13
main.go
13
main.go
|
@ -220,7 +220,7 @@ var (
|
|||
filesToTrash = append(filesToTrash, file)
|
||||
}
|
||||
|
||||
// if none of the args were files, then process find files based on filter
|
||||
// if none of the args were files, then find files based on filter
|
||||
if len(filesToTrash) == 0 {
|
||||
fls, err := files.FindDisk(workdir, recursive, fltr)
|
||||
if err != nil {
|
||||
|
@ -255,7 +255,6 @@ var (
|
|||
Action: func(_ *cli.Context) error {
|
||||
log.Debugf("searching in directory %s for files", trashDir)
|
||||
|
||||
// look for files
|
||||
fls, err := files.FindTrash(trashDir, ogdir, fltr)
|
||||
|
||||
var msg string
|
||||
|
@ -273,10 +272,7 @@ var (
|
|||
return err
|
||||
}
|
||||
|
||||
// display them
|
||||
_, _, err = interactive.Select(fls, termwidth, termheight, true, noInterArg, workdir, modes.Listing)
|
||||
|
||||
return err
|
||||
return interactive.Show(fls, termwidth, termheight, noInterArg, workdir)
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -290,7 +286,6 @@ var (
|
|||
Action: func(_ *cli.Context) error {
|
||||
log.Debugf("searching in directory %s for files", trashDir)
|
||||
|
||||
// look for files
|
||||
fls, err := files.FindTrash(trashDir, ogdir, fltr)
|
||||
if len(fls) == 0 {
|
||||
fmt.Fprintln(os.Stdout, "no files to restore")
|
||||
|
@ -299,7 +294,7 @@ var (
|
|||
return err
|
||||
}
|
||||
|
||||
selected, _, err := interactive.Select(fls, termwidth, termheight, false, all, workdir, modes.Restoring)
|
||||
selected, _, err := interactive.Select(fls, termwidth, termheight, all, all, workdir, modes.Restoring)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -328,7 +323,7 @@ var (
|
|||
return err
|
||||
}
|
||||
|
||||
selected, _, err := interactive.Select(fls, termwidth, termheight, false, all, workdir, modes.Cleaning)
|
||||
selected, _, err := interactive.Select(fls, termwidth, termheight, all, all, workdir, modes.Cleaning)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue