2023-11-04 12:20:13 -06:00
|
|
|
package cli
|
2023-10-30 15:23:07 -06:00
|
|
|
|
|
|
|
import (
|
2023-11-12 00:19:45 -07:00
|
|
|
"fmt"
|
2023-10-30 15:23:07 -06:00
|
|
|
"os"
|
|
|
|
"os/exec"
|
2023-11-04 16:50:45 -06:00
|
|
|
"strings"
|
2023-11-12 00:19:45 -07:00
|
|
|
"time"
|
2023-10-30 15:23:07 -06:00
|
|
|
)
|
|
|
|
|
2023-11-04 13:58:48 -06:00
|
|
|
// InputFromEditor retrieves user input by opening an editor (one specified by
|
|
|
|
// $EDITOR or 'vim' if $EDITOR is not set) on a temporary file. Once the editor
|
|
|
|
// closes, the contents of the file are read and the file is deleted. If the
|
|
|
|
// contents of the file exactly match the value of placeholder (no edits to the
|
|
|
|
// file were made), then an empty string is returned. Otherwise, the contents
|
|
|
|
// are returned. Example patten: message.*.md
|
2023-10-30 15:23:07 -06:00
|
|
|
func InputFromEditor(placeholder string, pattern string) (string, error) {
|
|
|
|
msgFile, _ := os.CreateTemp("/tmp", pattern)
|
|
|
|
defer os.Remove(msgFile.Name())
|
|
|
|
|
|
|
|
os.WriteFile(msgFile.Name(), []byte(placeholder), os.ModeAppend)
|
|
|
|
|
|
|
|
editor := os.Getenv("EDITOR")
|
|
|
|
if editor == "" {
|
|
|
|
editor = "vim" // default to vim if no EDITOR env variable
|
|
|
|
}
|
|
|
|
|
|
|
|
execCmd := exec.Command(editor, msgFile.Name())
|
|
|
|
execCmd.Stdin = os.Stdin
|
|
|
|
execCmd.Stdout = os.Stdout
|
|
|
|
execCmd.Stderr = os.Stderr
|
|
|
|
|
|
|
|
if err := execCmd.Run(); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
bytes, _ := os.ReadFile(msgFile.Name())
|
|
|
|
content := string(bytes)
|
|
|
|
|
2023-11-04 16:50:45 -06:00
|
|
|
if placeholder != "" {
|
|
|
|
if content == placeholder {
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// strip placeholder if content begins with it
|
|
|
|
if strings.HasPrefix(content, placeholder) {
|
|
|
|
content = content[len(placeholder):]
|
|
|
|
}
|
2023-10-30 15:23:07 -06:00
|
|
|
}
|
|
|
|
|
2023-11-05 01:22:45 -06:00
|
|
|
return strings.Trim(content, "\n \t"), nil
|
2023-10-30 15:23:07 -06:00
|
|
|
}
|
2023-11-12 00:19:45 -07:00
|
|
|
|
|
|
|
// humanTimeElapsedSince returns a human-friendly representation of the given time
|
|
|
|
// duration.
|
|
|
|
func humanTimeElapsedSince(d time.Duration) string {
|
|
|
|
seconds := d.Seconds()
|
|
|
|
minutes := seconds / 60
|
|
|
|
hours := minutes / 60
|
|
|
|
days := hours / 24
|
|
|
|
weeks := days / 7
|
|
|
|
months := days / 30
|
|
|
|
years := days / 365
|
|
|
|
|
|
|
|
switch {
|
|
|
|
case seconds < 60:
|
|
|
|
return "seconds ago"
|
|
|
|
case minutes < 2:
|
|
|
|
return "1 minute ago"
|
|
|
|
case minutes < 60:
|
|
|
|
return fmt.Sprintf("%d minutes ago", int64(minutes))
|
|
|
|
case hours < 2:
|
|
|
|
return "1 hour ago"
|
|
|
|
case hours < 24:
|
|
|
|
return fmt.Sprintf("%d hours ago", int64(hours))
|
|
|
|
case days < 2:
|
|
|
|
return "1 day ago"
|
|
|
|
case days < 7:
|
|
|
|
return fmt.Sprintf("%d days ago", int64(days))
|
|
|
|
case weeks < 2:
|
|
|
|
return "1 week ago"
|
|
|
|
case weeks <= 4:
|
|
|
|
return fmt.Sprintf("%d weeks ago", int64(weeks))
|
|
|
|
case months < 2:
|
|
|
|
return "1 month ago"
|
|
|
|
case months < 12:
|
|
|
|
return fmt.Sprintf("%d months ago", int64(months))
|
|
|
|
case years < 2:
|
|
|
|
return "1 year ago"
|
|
|
|
default:
|
|
|
|
return fmt.Sprintf("%d years ago", int64(years))
|
|
|
|
}
|
|
|
|
}
|