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 questionDlg bool
entryDlg bool entryDlg bool
listDlg bool listDlg bool
calendarDlg bool
passwordDlg bool passwordDlg bool
fileSelectionDlg bool fileSelectionDlg bool
colorSelectionDlg bool colorSelectionDlg bool
@ -66,6 +67,11 @@ var (
columns int columns int
allowEmpty bool allowEmpty bool
// Calendar options
year uint
month uint
day uint
// File selection options // File selection options
save bool save bool
directory bool directory bool
@ -145,6 +151,9 @@ func main() {
strResult(zenity.List(text, flag.Args(), opts...)) strResult(zenity.List(text, flag.Args(), opts...))
} }
case calendarDlg:
calResult(zenity.Calendar(text, opts...))
case passwordDlg: case passwordDlg:
_, pw, err := zenity.Password(opts...) _, pw, err := zenity.Password(opts...)
strResult(pw, err) strResult(pw, err)
@ -181,6 +190,7 @@ func setupFlags() {
flag.BoolVar(&questionDlg, "question", false, "Display question dialog") flag.BoolVar(&questionDlg, "question", false, "Display question dialog")
flag.BoolVar(&entryDlg, "entry", false, "Display text entry dialog") flag.BoolVar(&entryDlg, "entry", false, "Display text entry dialog")
flag.BoolVar(&listDlg, "list", false, "Display list 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(&passwordDlg, "password", false, "Display password dialog")
flag.BoolVar(&fileSelectionDlg, "file-selection", false, "Display file selection dialog") flag.BoolVar(&fileSelectionDlg, "file-selection", false, "Display file selection dialog")
flag.BoolVar(&colorSelectionDlg, "color-selection", false, "Display color 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.Bool("hide-header", true, "Hide the column headers")
flag.BoolVar(&allowEmpty, "allow-empty", true, "Allow empty selection (macOS only)") 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 // File selection options
flag.BoolVar(&save, "save", false, "Activate save mode") flag.BoolVar(&save, "save", false, "Activate save mode")
flag.BoolVar(&directory, "directory", false, "Activate directory-only selection") flag.BoolVar(&directory, "directory", false, "Activate directory-only selection")
@ -283,6 +299,9 @@ func validateFlags() {
if listDlg { if listDlg {
n++ n++
} }
if calendarDlg {
n++
}
if passwordDlg { if passwordDlg {
n++ n++
} }
@ -341,13 +360,18 @@ func loadFlags() []zenity.Option {
setDefault(&text, "Select items from the list below:") setDefault(&text, "Select items from the list below:")
setDefault(&okLabel, "OK") setDefault(&okLabel, "OK")
setDefault(&cancelLabel, "Cancel") setDefault(&cancelLabel, "Cancel")
case calendarDlg:
setDefault(&title, "Calendar selection")
setDefault(&text, "Select a date from below:")
setDefault(&okLabel, "OK")
setDefault(&cancelLabel, "Cancel")
case passwordDlg: case passwordDlg:
setDefault(&title, "Type your password") setDefault(&title, "Type your password")
setDefault(&okLabel, "OK") setDefault(&okLabel, "OK")
setDefault(&cancelLabel, "Cancel") setDefault(&cancelLabel, "Cancel")
case progressDlg: case progressDlg:
setDefault(&title, "Progress") setDefault(&title, "Progress")
setDefault(&text, "Running...") setDefault(&text, "Running")
setDefault(&okLabel, "OK") setDefault(&okLabel, "OK")
setDefault(&cancelLabel, "Cancel") setDefault(&cancelLabel, "Cancel")
} }
@ -413,6 +437,18 @@ func loadFlags() []zenity.Option {
opts = append(opts, zenity.DisallowEmpty()) 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 // File selection options
if directory { if directory {
@ -484,6 +520,12 @@ func lstResult(l []string, err error) {
os.Stdout.WriteString(zenutil.LineBreak) 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) { func colResult(c color.Color, err error) {
errResult(err) errResult(err)
os.Stdout.WriteString(zenutil.UnparseColor(c)) 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 var date zenutil.Date
date.OK, date.Cancel, date.Extra = getAlertButtons(opts) date.OK, date.Cancel, date.Extra = getAlertButtons(opts)
date.Format = "yyyy-MM-dd" date.Format = zenutil.StrftimeUTS35(zenutil.DateFormat)
if opts.time != nil { if opts.time != nil {
date.Date = opts.time.Unix() date.Date = opts.time.Unix()
} }
@ -27,5 +27,5 @@ func calendar(text string, opts options) (time.Time, error) {
if err != nil { if err != nil {
return time.Time{}, err 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) { 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 = appendTitle(args, opts)
args = appendButtons(args, opts) args = appendButtons(args, opts)
args = appendWidthHeight(args, opts) args = appendWidthHeight(args, opts)
@ -27,5 +27,5 @@ func calendar(text string, opts options) (time.Time, error) {
if err != nil { if err != nil {
return time.Time{}, err 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 Timeout int
LineBreak = "\n" LineBreak = "\n"
Separator = "\x00" Separator = "\x00"
DateFormat = "%F"
) )

View file

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

View file

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

View file

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