Skip to content

Commit

Permalink
feat: more tree commands and status messages
Browse files Browse the repository at this point in the history
  • Loading branch information
mistakenelf committed Mar 12, 2024
1 parent 299502c commit 94bac41
Show file tree
Hide file tree
Showing 11 changed files with 356 additions and 158 deletions.
3 changes: 0 additions & 3 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ linters:
disable-all: true
enable:
- bodyclose
- deadcode
- dogsled
- errcheck
- exportloopref
Expand All @@ -23,13 +22,11 @@ linters:
- nolintlint
- rowserrcheck
- staticcheck
- structcheck
- stylecheck
- typecheck
- unconvert
- unparam
- unused
- varcheck
- whitespace
- wastedassign
- nilerr
Expand Down
140 changes: 134 additions & 6 deletions filetree/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ import (
"fmt"
"os"
"path/filepath"
"time"

"github.com/atotto/clipboard"
tea "github.com/charmbracelet/bubbletea"
"github.com/mistakenelf/fm/filesystem"
)

type getDirectoryListingMsg []DirectoryItem
type errorMsg error
type errorMsg string
type copyToClipboardMsg string
type statusMessageTimeoutMsg struct{}

// getDirectoryListingCmd updates the directory listing based on the name of the directory provided.
func getDirectoryListingCmd(directoryName string, showHidden bool) tea.Cmd {
Expand All @@ -21,13 +25,13 @@ func getDirectoryListingCmd(directoryName string, showHidden bool) tea.Cmd {
if directoryName == filesystem.HomeDirectory {
directoryName, err = filesystem.GetHomeDirectory()
if err != nil {
return errorMsg(err)
return errorMsg(err.Error())
}
}

directoryInfo, err := os.Stat(directoryName)
if err != nil {
return errorMsg(err)
return errorMsg(err.Error())
}

if !directoryInfo.IsDir() {
Expand All @@ -36,17 +40,17 @@ func getDirectoryListingCmd(directoryName string, showHidden bool) tea.Cmd {

err = os.Chdir(directoryName)
if err != nil {
return errorMsg(err)
return errorMsg(err.Error())
}

files, err := filesystem.GetDirectoryListing(directoryName, showHidden)
if err != nil {
return errorMsg(err)
return errorMsg(err.Error())
}

workingDirectory, err := filesystem.GetWorkingDirectory()
if err != nil {
return errorMsg(err)
return errorMsg(err.Error())
}

for _, file := range files {
Expand All @@ -72,3 +76,127 @@ func getDirectoryListingCmd(directoryName string, showHidden bool) tea.Cmd {
return getDirectoryListingMsg(directoryItems)
}
}

// deleteDirectoryItemCmd deletes a directory based on the name provided.
func deleteDirectoryItemCmd(name string, isDirectory bool) tea.Cmd {
return func() tea.Msg {
if isDirectory {
if err := filesystem.DeleteDirectory(name); err != nil {
return errorMsg(err.Error())
}
} else {
if err := filesystem.DeleteFile(name); err != nil {
return errorMsg(err.Error())
}
}

return nil
}
}

// createDirectoryCmd creates a directory based on the name provided.
func createDirectoryCmd(name string) tea.Cmd {

Check failure on line 98 in filetree/commands.go

View workflow job for this annotation

GitHub Actions / lint

func `createDirectoryCmd` is unused (unused)
return func() tea.Msg {
if err := filesystem.CreateDirectory(name); err != nil {
return errorMsg(err.Error())
}

return nil
}
}

// createFileCmd creates a file based on the name provided.
func createFileCmd(name string) tea.Cmd {

Check failure on line 109 in filetree/commands.go

View workflow job for this annotation

GitHub Actions / lint

func `createFileCmd` is unused (unused)
return func() tea.Msg {
if err := filesystem.CreateFile(name); err != nil {
return errorMsg(err.Error())
}

return nil
}
}

// zipDirectoryCmd zips a directory based on the name provided.
func zipDirectoryCmd(name string) tea.Cmd {
return func() tea.Msg {
if err := filesystem.Zip(name); err != nil {
return errorMsg(err.Error())
}

return nil
}
}

// unzipDirectoryCmd unzips a directory based on the name provided.
func unzipDirectoryCmd(name string) tea.Cmd {
return func() tea.Msg {
if err := filesystem.Unzip(name); err != nil {
return errorMsg(err.Error())
}

return nil
}
}

// copyDirectoryItemCmd copies a directory based on the name provided.
func copyDirectoryItemCmd(name string, isDirectory bool) tea.Cmd {
return func() tea.Msg {
if isDirectory {
if err := filesystem.CopyDirectory(name); err != nil {
return errorMsg(err.Error())
}
} else {
if err := filesystem.CopyFile(name); err != nil {
return errorMsg(err.Error())
}
}

return nil
}
}

// copyToClipboardCmd copies the provided string to the clipboard.
func copyToClipboardCmd(name string) tea.Cmd {
return func() tea.Msg {
workingDir, err := filesystem.GetWorkingDirectory()
if err != nil {
return errorMsg(err.Error())
}

filePath := filepath.Join(workingDir, name)
err = clipboard.WriteAll(filePath)
if err != nil {
return errorMsg(err.Error())
}

return copyToClipboardMsg(fmt.Sprintf("%s %s %s", "Successfully copied", filePath, "to clipboard"))
}
}

// writeSelectionPathCmd writes content to the file specified.
func writeSelectionPathCmd(selectionPath, filePath string) tea.Cmd {

Check failure on line 177 in filetree/commands.go

View workflow job for this annotation

GitHub Actions / lint

func `writeSelectionPathCmd` is unused (unused)
return func() tea.Msg {
if err := filesystem.WriteToFile(selectionPath, filePath); err != nil {
return errorMsg(err.Error())
}

return nil
}
}

// NewStatusMessage sets a new status message, which will show for a limited
// amount of time. Note that this also returns a command.
func (m *Model) NewStatusMessage(s string) tea.Cmd {
m.StatusMessage = s
if m.statusMessageTimer != nil {
m.statusMessageTimer.Stop()
}

m.statusMessageTimer = time.NewTimer(m.StatusMessageLifetime)

// Wait for timeout
return func() tea.Msg {
<-m.statusMessageTimer.C
return statusMessageTimeoutMsg{}
}
}
58 changes: 36 additions & 22 deletions filetree/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,45 @@ package filetree
import "github.com/charmbracelet/bubbles/key"

type KeyMap struct {
Down key.Binding
Up key.Binding
GoToTop key.Binding
GoToBottom key.Binding
PageUp key.Binding
PageDown key.Binding
GoToHomeDirectory key.Binding
GoToRootDirectory key.Binding
ToggleHidden key.Binding
OpenDirectory key.Binding
PreviousDirectory key.Binding
Down key.Binding
Up key.Binding
GoToTop key.Binding
GoToBottom key.Binding
PageUp key.Binding
PageDown key.Binding
GoToHomeDirectory key.Binding
GoToRootDirectory key.Binding
ToggleHidden key.Binding
OpenDirectory key.Binding
PreviousDirectory key.Binding
CopyPathToClipboard key.Binding
CopyDirectoryItem key.Binding
DeleteDirectoryItem key.Binding
ZipDirectoryItem key.Binding
UnzipDirectoryItem key.Binding
ShowDirectoriesOnly key.Binding
ShowFilesOnly key.Binding
}

func DefaultKeyMap() KeyMap {
return KeyMap{
Down: key.NewBinding(key.WithKeys("j", "down", "ctrl+n"), key.WithHelp("j", "down")),
Up: key.NewBinding(key.WithKeys("k", "up", "ctrl+p"), key.WithHelp("k", "up")),
GoToTop: key.NewBinding(key.WithKeys("g"), key.WithHelp("g", "go to top")),
GoToBottom: key.NewBinding(key.WithKeys("G"), key.WithHelp("G", "go to bottom")),
PageUp: key.NewBinding(key.WithKeys("K", "pgup"), key.WithHelp("pgup", "page up")),
PageDown: key.NewBinding(key.WithKeys("J", "pgdown"), key.WithHelp("pgdown", "page down")),
GoToHomeDirectory: key.NewBinding(key.WithKeys("~"), key.WithHelp("~", "go to home directory")),
GoToRootDirectory: key.NewBinding(key.WithKeys("/"), key.WithHelp("/", "go to root directory")),
ToggleHidden: key.NewBinding(key.WithKeys("."), key.WithHelp(".", "toggle hidden")),
OpenDirectory: key.NewBinding(key.WithKeys("l", "right"), key.WithHelp("l", "open directory")),
PreviousDirectory: key.NewBinding(key.WithKeys("h", "left"), key.WithHelp("h", "previous directory")),
Down: key.NewBinding(key.WithKeys("j", "down", "ctrl+n"), key.WithHelp("j", "down")),
Up: key.NewBinding(key.WithKeys("k", "up", "ctrl+p"), key.WithHelp("k", "up")),
GoToTop: key.NewBinding(key.WithKeys("g"), key.WithHelp("g", "go to top")),
GoToBottom: key.NewBinding(key.WithKeys("G"), key.WithHelp("G", "go to bottom")),
PageUp: key.NewBinding(key.WithKeys("K", "pgup"), key.WithHelp("pgup", "page up")),
PageDown: key.NewBinding(key.WithKeys("J", "pgdown"), key.WithHelp("pgdown", "page down")),
GoToHomeDirectory: key.NewBinding(key.WithKeys("~"), key.WithHelp("~", "go to home directory")),
GoToRootDirectory: key.NewBinding(key.WithKeys("/"), key.WithHelp("/", "go to root directory")),
ToggleHidden: key.NewBinding(key.WithKeys("."), key.WithHelp(".", "toggle hidden")),
OpenDirectory: key.NewBinding(key.WithKeys("l", "right"), key.WithHelp("l", "open directory")),
PreviousDirectory: key.NewBinding(key.WithKeys("h", "left"), key.WithHelp("h", "previous directory")),
CopyPathToClipboard: key.NewBinding(key.WithKeys("y"), key.WithHelp("y", "copy to clipboard")),
CopyDirectoryItem: key.NewBinding(key.WithKeys("C"), key.WithHelp("C", "copy directory item")),
DeleteDirectoryItem: key.NewBinding(key.WithKeys("X"), key.WithHelp("X", "delete directory item")),
ZipDirectoryItem: key.NewBinding(key.WithKeys("Z"), key.WithHelp("Z", "zip directory item")),
UnzipDirectoryItem: key.NewBinding(key.WithKeys("U"), key.WithHelp("U", "unzip directory item")),
ShowDirectoriesOnly: key.NewBinding(key.WithKeys("D"), key.WithHelp("D", "show directories only")),
ShowFilesOnly: key.NewBinding(key.WithKeys("F"), key.WithHelp("F", "show files only")),
}
}
4 changes: 3 additions & 1 deletion filetree/methods.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package filetree

import "fmt"
import (
"fmt"
)

const (
thousand = 1000
Expand Down
45 changes: 27 additions & 18 deletions filetree/model.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package filetree

import "github.com/mistakenelf/fm/filesystem"
import (
"time"

"github.com/mistakenelf/fm/filesystem"
)

type DirectoryItem struct {
Name string
Expand All @@ -12,16 +16,19 @@ type DirectoryItem struct {
}

type Model struct {
Cursor int
files []DirectoryItem
Active bool
keyMap KeyMap
min int
max int
height int
width int
startDir string
showHidden bool
Cursor int
files []DirectoryItem
Active bool
keyMap KeyMap
min int
max int
height int
width int
startDir string
showHidden bool
StatusMessage string
StatusMessageLifetime time.Duration
statusMessageTimer *time.Timer
}

func New(active bool, startDir string) Model {
Expand All @@ -32,12 +39,14 @@ func New(active bool, startDir string) Model {
}

return Model{
Cursor: 0,
Active: active,
keyMap: DefaultKeyMap(),
min: 0,
max: 0,
startDir: startingDirectory,
showHidden: true,
Cursor: 0,
Active: active,
keyMap: DefaultKeyMap(),
min: 0,
max: 0,
startDir: startingDirectory,
showHidden: true,
StatusMessage: "",
StatusMessageLifetime: time.Second,
}
}
29 changes: 29 additions & 0 deletions filetree/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/charmbracelet/bubbles/key"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/mistakenelf/fm/filesystem"
)

Expand All @@ -18,6 +19,12 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
}

switch msg := msg.(type) {
case errorMsg:
cmds = append(cmds, m.NewStatusMessage(lipgloss.NewStyle().Foreground(lipgloss.Color("#cc241d")).Bold(true).Render(string(msg))))
case statusMessageTimeoutMsg:
m.StatusMessage = ""
case copyToClipboardMsg:
m.StatusMessage = string(msg)
case getDirectoryListingMsg:
if msg != nil {
m.files = msg
Expand Down Expand Up @@ -94,6 +101,28 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
}
case key.Matches(msg, m.keyMap.PreviousDirectory):
return m, getDirectoryListingCmd(filepath.Dir(m.files[m.Cursor].CurrentDirectory), m.showHidden)
case key.Matches(msg, m.keyMap.CopyPathToClipboard):
return m, copyToClipboardCmd(m.files[m.Cursor].Name)
case key.Matches(msg, m.keyMap.CopyDirectoryItem):
return m, tea.Sequence(
copyDirectoryItemCmd(m.files[m.Cursor].Name, m.files[m.Cursor].IsDirectory),
getDirectoryListingCmd(filesystem.CurrentDirectory, m.showHidden),
)
case key.Matches(msg, m.keyMap.DeleteDirectoryItem):
return m, tea.Sequence(
deleteDirectoryItemCmd(m.files[m.Cursor].Name, m.files[m.Cursor].IsDirectory),
getDirectoryListingCmd(filesystem.CurrentDirectory, m.showHidden),
)
case key.Matches(msg, m.keyMap.ZipDirectoryItem):
return m, tea.Sequence(
zipDirectoryCmd(m.files[m.Cursor].Name),
getDirectoryListingCmd(filesystem.CurrentDirectory, m.showHidden),
)
case key.Matches(msg, m.keyMap.UnzipDirectoryItem):
return m, tea.Sequence(
unzipDirectoryCmd(m.files[m.Cursor].Name),
getDirectoryListingCmd(filesystem.CurrentDirectory, m.showHidden),
)
}
}

Expand Down
Loading

0 comments on commit 94bac41

Please sign in to comment.