Calendar command.
This commit is contained in:
parent
f47c02b6d1
commit
198d2504fe
8 changed files with 233 additions and 33 deletions
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
151
internal/zenutil/date.go
Normal 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()
|
||||
}
|
|
@ -2,8 +2,9 @@ package zenutil
|
|||
|
||||
// These are internal.
|
||||
var (
|
||||
Command bool
|
||||
Timeout int
|
||||
LineBreak = "\n"
|
||||
Separator = "\x00"
|
||||
Command bool
|
||||
Timeout int
|
||||
LineBreak = "\n"
|
||||
Separator = "\x00"
|
||||
DateFormat = "%F"
|
||||
)
|
||||
|
|
|
@ -5,8 +5,9 @@ package zenutil
|
|||
|
||||
// These are internal.
|
||||
var (
|
||||
Command bool
|
||||
Timeout int
|
||||
LineBreak = "\n"
|
||||
Separator = "\x1e"
|
||||
Command bool
|
||||
Timeout int
|
||||
LineBreak = "\n"
|
||||
Separator = "\x1e"
|
||||
DateFormat = "%F"
|
||||
)
|
||||
|
|
|
@ -2,8 +2,9 @@ package zenutil
|
|||
|
||||
// These are internal.
|
||||
var (
|
||||
Command bool
|
||||
Timeout int
|
||||
Separator string
|
||||
LineBreak = "\r\n"
|
||||
Command bool
|
||||
Timeout int
|
||||
Separator string
|
||||
LineBreak = "\r\n"
|
||||
DateFormat = "%F"
|
||||
)
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue