Calendar command.

This commit is contained in:
Nuno Cruces 2022-03-29 12:53:20 +01:00
parent f47c02b6d1
commit 198d2504fe
8 changed files with 233 additions and 33 deletions

View file

@ -36,6 +36,7 @@ var (
questionDlg bool
entryDlg bool
listDlg bool
calendarDlg bool
passwordDlg bool
fileSelectionDlg bool
colorSelectionDlg bool
@ -66,6 +67,11 @@ var (
columns int
allowEmpty bool
// Calendar options
year uint
month uint
day uint
// File selection options
save bool
directory bool
@ -145,6 +151,9 @@ func main() {
strResult(zenity.List(text, flag.Args(), opts...))
}
case calendarDlg:
calResult(zenity.Calendar(text, opts...))
case passwordDlg:
_, pw, err := zenity.Password(opts...)
strResult(pw, err)
@ -181,6 +190,7 @@ func setupFlags() {
flag.BoolVar(&questionDlg, "question", false, "Display question dialog")
flag.BoolVar(&entryDlg, "entry", false, "Display text entry dialog")
flag.BoolVar(&listDlg, "list", false, "Display list dialog")
flag.BoolVar(&calendarDlg, "calendar", false, "Display calendar dialog")
flag.BoolVar(&passwordDlg, "password", false, "Display password dialog")
flag.BoolVar(&fileSelectionDlg, "file-selection", false, "Display file selection dialog")
flag.BoolVar(&colorSelectionDlg, "color-selection", false, "Display color selection dialog")
@ -214,6 +224,12 @@ func setupFlags() {
flag.Bool("hide-header", true, "Hide the column headers")
flag.BoolVar(&allowEmpty, "allow-empty", true, "Allow empty selection (macOS only)")
// Calendar options
flag.UintVar(&year, "year", 0, "Set the calendar `year`")
flag.UintVar(&month, "month", 0, "Set the calendar `month`")
flag.UintVar(&day, "day", 0, "Set the calendar `day`")
flag.StringVar(&zenutil.DateFormat, "date-format", "%m/%d/%Y", "Set the `format` for the returned date")
// File selection options
flag.BoolVar(&save, "save", false, "Activate save mode")
flag.BoolVar(&directory, "directory", false, "Activate directory-only selection")
@ -283,6 +299,9 @@ func validateFlags() {
if listDlg {
n++
}
if calendarDlg {
n++
}
if passwordDlg {
n++
}
@ -341,13 +360,18 @@ func loadFlags() []zenity.Option {
setDefault(&text, "Select items from the list below:")
setDefault(&okLabel, "OK")
setDefault(&cancelLabel, "Cancel")
case calendarDlg:
setDefault(&title, "Calendar selection")
setDefault(&text, "Select a date from below:")
setDefault(&okLabel, "OK")
setDefault(&cancelLabel, "Cancel")
case passwordDlg:
setDefault(&title, "Type your password")
setDefault(&okLabel, "OK")
setDefault(&cancelLabel, "Cancel")
case progressDlg:
setDefault(&title, "Progress")
setDefault(&text, "Running...")
setDefault(&text, "Running")
setDefault(&okLabel, "OK")
setDefault(&cancelLabel, "Cancel")
}
@ -413,6 +437,18 @@ func loadFlags() []zenity.Option {
opts = append(opts, zenity.DisallowEmpty())
}
y, m, d := time.Now().Date()
if month != 0 {
m = time.Month(month)
}
if day != 0 {
d = int(day)
}
if year != 0 {
y = int(year)
}
opts = append(opts, zenity.DefaultDate(y, m, d))
// File selection options
if directory {
@ -484,6 +520,12 @@ func lstResult(l []string, err error) {
os.Stdout.WriteString(zenutil.LineBreak)
}
func calResult(d time.Time, err error) {
errResult(err)
os.Stdout.WriteString(d.Format(zenutil.Strftime(zenutil.DateFormat)))
os.Stdout.WriteString(zenutil.LineBreak)
}
func colResult(c color.Color, err error) {
errResult(err)
os.Stdout.WriteString(zenutil.UnparseColor(c))

View file

@ -10,7 +10,7 @@ func calendar(text string, opts options) (time.Time, error) {
var date zenutil.Date
date.OK, date.Cancel, date.Extra = getAlertButtons(opts)
date.Format = "yyyy-MM-dd"
date.Format = zenutil.StrftimeUTS35(zenutil.DateFormat)
if opts.time != nil {
date.Date = opts.time.Unix()
}
@ -27,5 +27,5 @@ func calendar(text string, opts options) (time.Time, error) {
if err != nil {
return time.Time{}, err
}
return time.Parse("2006-01-02", str)
return time.Parse(zenutil.Strftime(zenutil.DateFormat), str)
}

View file

@ -10,7 +10,7 @@ import (
)
func calendar(text string, opts options) (time.Time, error) {
args := []string{"--calendar", "--text", text, "--date-format=%F"}
args := []string{"--calendar", "--text", text, "--date-format", zenutil.DateFormat}
args = appendTitle(args, opts)
args = appendButtons(args, opts)
args = appendWidthHeight(args, opts)
@ -27,5 +27,5 @@ func calendar(text string, opts options) (time.Time, error) {
if err != nil {
return time.Time{}, err
}
return time.Parse("2006-01-02", str)
return time.Parse(zenutil.Strftime(zenutil.DateFormat), str)
}

151
internal/zenutil/date.go Normal file
View file

@ -0,0 +1,151 @@
package zenutil
import "strings"
// https://strftime.org/
var strftimeTable = map[byte]string{
'B': "January",
'b': "Jan",
'h': "Jan",
'm': "01",
'A': "Monday",
'a': "Mon",
'e': "_2",
'd': "02",
'j': "002",
'H': "15",
'I': "03",
'M': "04",
'S': "05",
'Y': "2006",
'y': "06",
'p': "PM",
'Z': "MST",
'z': "-0700",
'L': "000",
'f': "000000",
'+': "Mon Jan _2 03:04:05 PM MST 2006",
'c': "Mon Jan _2 15:04:05 2006",
'F': "2006-01-02",
'D': "01/02/06",
'x': "01/02/06",
'r': "03:04:05 PM",
'T': "15:04:05",
'X': "15:04:05",
'R': "15:04",
'%': "%",
't': "\t",
'n': LineBreak,
}
// Strftime is internal.
func Strftime(fmt string) string {
var res strings.Builder
res.Grow(len(fmt))
const (
initial = iota
special
)
state := initial
for _, b := range []byte(fmt) {
switch state {
case initial:
if b == '%' {
state = special
} else {
res.WriteByte(b)
state = initial
}
case special:
s, ok := strftimeTable[b]
if ok {
res.WriteString(s)
} else {
res.WriteByte(b)
}
state = initial
}
}
return res.String()
}
// https://nsdateformatter.com/
var strftimeUTS35Table = map[byte]string{
'B': "MMMM",
'b': "MMM",
'h': "MMM",
'm': "MM",
'A': "EEEE",
'a': "E",
'd': "dd",
'j': "DDD",
'H': "HH",
'I': "hh",
'M': "mm",
'S': "ss",
'Y': "yyyy",
'y': "yy",
'G': "YYYY",
'g': "YY",
'V': "ww",
'p': "a",
'Z': "zzz",
'z': "Z",
'L': "SSS",
'f': "SSSSSS",
'+': "E MMM d hh:mm:ss a zzz yyyy",
'c': "E MMM d HH:mm:ss yyyy",
'F': "yyyy-MM-dd",
'D': "MM/dd/yy",
'x': "MM/dd/yy",
'r': "hh:mm:ss a",
'T': "HH:mm:ss",
'X': "HH:mm:ss",
'R': "HH:mm",
'%': "%",
't': "\t",
'n': LineBreak,
}
// StrftimeUTS35 is internal.
func StrftimeUTS35(fmt string) string {
var res strings.Builder
res.Grow(len(fmt))
const (
initial = iota
special
)
state := initial
for _, b := range []byte(fmt) {
switch state {
case initial:
if b == '%' {
state = special
} else {
res.WriteByte(b)
state = initial
}
case special:
s, ok := strftimeUTS35Table[b]
if ok {
res.WriteString(s)
} else {
res.WriteByte(b)
}
state = initial
}
}
return res.String()
}

View file

@ -6,4 +6,5 @@ var (
Timeout int
LineBreak = "\n"
Separator = "\x00"
DateFormat = "%F"
)

View file

@ -9,4 +9,5 @@ var (
Timeout int
LineBreak = "\n"
Separator = "\x1e"
DateFormat = "%F"
)

View file

@ -6,4 +6,5 @@ var (
Timeout int
Separator string
LineBreak = "\r\n"
DateFormat = "%F"
)

View file

@ -1,5 +1,7 @@
package zenutil
import "strings"
// Unescape is internal.
func Unescape(s string) string {
// Apply rules described in:
@ -12,7 +14,7 @@ func Unescape(s string) string {
escape3
)
var oct byte
var res []byte
var res strings.Builder
state := initial
for _, b := range []byte(s) {
switch state {
@ -21,7 +23,7 @@ func Unescape(s string) string {
case '\\':
state = escape1
default:
res = append(res, b)
res.WriteByte(b)
state = initial
}
@ -31,25 +33,25 @@ func Unescape(s string) string {
oct = b - '0'
state = escape2
case 'b':
res = append(res, '\b')
res.WriteByte('\b')
state = initial
case 'f':
res = append(res, '\f')
res.WriteByte('\f')
state = initial
case 'n':
res = append(res, '\n')
res.WriteByte('\n')
state = initial
case 'r':
res = append(res, '\r')
res.WriteByte('\r')
state = initial
case 't':
res = append(res, '\t')
res.WriteByte('\t')
state = initial
case 'v':
res = append(res, '\v')
res.WriteByte('\v')
state = initial
default:
res = append(res, b)
res.WriteByte(b)
state = initial
}
@ -59,10 +61,11 @@ func Unescape(s string) string {
oct = oct<<3 | (b - '0')
state = escape3
case '\\':
res = append(res, oct)
res.WriteByte(oct)
state = escape1
default:
res = append(res, oct, b)
res.WriteByte(oct)
res.WriteByte(b)
state = initial
}
@ -70,20 +73,21 @@ func Unescape(s string) string {
switch b {
case '0', '1', '2', '3', '4', '5', '6', '7':
oct = oct<<3 | (b - '0')
res = append(res, oct)
res.WriteByte(oct)
state = initial
case '\\':
res = append(res, oct)
res.WriteByte(oct)
state = escape1
default:
res = append(res, oct, b)
res.WriteByte(oct)
res.WriteByte(b)
state = initial
}
}
}
if state == escape2 || state == escape3 {
res = append(res, oct)
res.WriteByte(oct)
}
return string(res)
return res.String()
}