@@ -131,18 +131,25 @@ func newCalendarEventsCmd(flags *rootFlags) *cobra.Command {
131131 var max int64
132132 var page string
133133 var query string
134+ var all bool
134135
135136 cmd := & cobra.Command {
136- Use : "events <calendarId>" ,
137- Short : "List events from a calendar" ,
138- Args : cobra .ExactArgs (1 ),
137+ Use : "events [ <calendarId>] " ,
138+ Short : "List events from a calendar or all calendars " ,
139+ Args : cobra .MaximumNArgs (1 ),
139140 RunE : func (cmd * cobra.Command , args []string ) error {
140- u := ui .FromContext (cmd .Context ())
141141 account , err := requireAccount (flags )
142142 if err != nil {
143143 return err
144144 }
145- calendarID := args [0 ]
145+
146+ // Validate args
147+ if ! all && len (args ) == 0 {
148+ return errors .New ("calendarId required unless --all is specified" )
149+ }
150+ if all && len (args ) > 0 {
151+ return errors .New ("calendarId not allowed with --all flag" )
152+ }
146153
147154 now := time .Now ().UTC ()
148155 oneWeekLater := now .Add (7 * 24 * time .Hour )
@@ -158,43 +165,12 @@ func newCalendarEventsCmd(flags *rootFlags) *cobra.Command {
158165 return err
159166 }
160167
161- call := svc .Events .List (calendarID ).
162- TimeMin (from ).
163- TimeMax (to ).
164- MaxResults (max ).
165- PageToken (page ).
166- SingleEvents (true ).
167- OrderBy ("startTime" )
168- if strings .TrimSpace (query ) != "" {
169- call = call .Q (query )
170- }
171- resp , err := call .Do ()
172- if err != nil {
173- return err
174- }
175- if outfmt .IsJSON (cmd .Context ()) {
176- return outfmt .WriteJSON (os .Stdout , map [string ]any {
177- "events" : resp .Items ,
178- "nextPageToken" : resp .NextPageToken ,
179- })
180- }
181-
182- if len (resp .Items ) == 0 {
183- u .Err ().Println ("No events" )
184- return nil
185- }
186-
187- tw := tabwriter .NewWriter (os .Stdout , 0 , 4 , 2 , ' ' , 0 )
188- fmt .Fprintln (tw , "ID\t START\t END\t SUMMARY" )
189- for _ , e := range resp .Items {
190- fmt .Fprintf (tw , "%s\t %s\t %s\t %s\n " , e .Id , eventStart (e ), eventEnd (e ), e .Summary )
168+ if all {
169+ return listAllCalendarsEvents (cmd , svc , from , to , max , page , query )
191170 }
192- _ = tw .Flush ()
193171
194- if resp .NextPageToken != "" {
195- u .Err ().Printf ("# Next page: --page %s" , resp .NextPageToken )
196- }
197- return nil
172+ calendarID := args [0 ]
173+ return listCalendarEvents (cmd , svc , calendarID , from , to , max , page , query )
198174 },
199175 }
200176
@@ -203,9 +179,154 @@ func newCalendarEventsCmd(flags *rootFlags) *cobra.Command {
203179 cmd .Flags ().Int64Var (& max , "max" , 10 , "Max results" )
204180 cmd .Flags ().StringVar (& page , "page" , "" , "Page token" )
205181 cmd .Flags ().StringVar (& query , "query" , "" , "Free text search" )
182+ cmd .Flags ().BoolVar (& all , "all" , false , "Fetch events from all calendars" )
206183 return cmd
207184}
208185
186+ func listCalendarEvents (cmd * cobra.Command , svc * calendar.Service , calendarID , from , to string , max int64 , page , query string ) error {
187+ u := ui .FromContext (cmd .Context ())
188+
189+ call := svc .Events .List (calendarID ).
190+ TimeMin (from ).
191+ TimeMax (to ).
192+ MaxResults (max ).
193+ PageToken (page ).
194+ SingleEvents (true ).
195+ OrderBy ("startTime" )
196+ if strings .TrimSpace (query ) != "" {
197+ call = call .Q (query )
198+ }
199+ resp , err := call .Do ()
200+ if err != nil {
201+ return err
202+ }
203+ if outfmt .IsJSON (cmd .Context ()) {
204+ return outfmt .WriteJSON (os .Stdout , map [string ]any {
205+ "events" : resp .Items ,
206+ "nextPageToken" : resp .NextPageToken ,
207+ })
208+ }
209+
210+ if len (resp .Items ) == 0 {
211+ u .Err ().Println ("No events" )
212+ return nil
213+ }
214+
215+ tw := tabwriter .NewWriter (os .Stdout , 0 , 4 , 2 , ' ' , 0 )
216+ fmt .Fprintln (tw , "ID\t START\t END\t SUMMARY" )
217+ for _ , e := range resp .Items {
218+ fmt .Fprintf (tw , "%s\t %s\t %s\t %s\n " , e .Id , eventStart (e ), eventEnd (e ), e .Summary )
219+ }
220+ _ = tw .Flush ()
221+
222+ if resp .NextPageToken != "" {
223+ u .Err ().Printf ("# Next page: --page %s" , resp .NextPageToken )
224+ }
225+ return nil
226+ }
227+
228+ type eventWithCalendar struct {
229+ * calendar.Event
230+ CalendarID string
231+ }
232+
233+ func listAllCalendarsEvents (cmd * cobra.Command , svc * calendar.Service , from , to string , max int64 , page , query string ) error {
234+ u := ui .FromContext (cmd .Context ())
235+
236+ // Get all calendars
237+ calResp , err := svc .CalendarList .List ().Do ()
238+ if err != nil {
239+ return err
240+ }
241+
242+ if len (calResp .Items ) == 0 {
243+ u .Err ().Println ("No calendars" )
244+ return nil
245+ }
246+
247+ // Collect events from all calendars
248+ var allEvents []* eventWithCalendar
249+ for _ , cal := range calResp .Items {
250+ call := svc .Events .List (cal .Id ).
251+ TimeMin (from ).
252+ TimeMax (to ).
253+ MaxResults (max ).
254+ PageToken (page ).
255+ SingleEvents (true ).
256+ OrderBy ("startTime" )
257+ if strings .TrimSpace (query ) != "" {
258+ call = call .Q (query )
259+ }
260+ resp , err := call .Do ()
261+ if err != nil {
262+ // Skip calendars that fail (e.g., due to permissions)
263+ continue
264+ }
265+ for _ , e := range resp .Items {
266+ allEvents = append (allEvents , & eventWithCalendar {
267+ Event : e ,
268+ CalendarID : cal .Id ,
269+ })
270+ }
271+ }
272+
273+ if len (allEvents ) == 0 {
274+ u .Err ().Println ("No events" )
275+ return nil
276+ }
277+
278+ // Sort events by start time
279+ sortEventsByStartTime (allEvents )
280+
281+ if outfmt .IsJSON (cmd .Context ()) {
282+ events := make ([]map [string ]any , 0 , len (allEvents ))
283+ for _ , e := range allEvents {
284+ eventMap := map [string ]any {
285+ "id" : e .Id ,
286+ "calendarId" : e .CalendarID ,
287+ "summary" : e .Summary ,
288+ "start" : e .Start ,
289+ "end" : e .End ,
290+ "status" : e .Status ,
291+ }
292+ if e .Description != "" {
293+ eventMap ["description" ] = e .Description
294+ }
295+ if e .Location != "" {
296+ eventMap ["location" ] = e .Location
297+ }
298+ if len (e .Attendees ) > 0 {
299+ eventMap ["attendees" ] = e .Attendees
300+ }
301+ events = append (events , eventMap )
302+ }
303+ return outfmt .WriteJSON (os .Stdout , map [string ]any {"events" : events })
304+ }
305+
306+ tw := tabwriter .NewWriter (os .Stdout , 0 , 4 , 2 , ' ' , 0 )
307+ fmt .Fprintln (tw , "CALENDAR\t ID\t START\t END\t SUMMARY" )
308+ for _ , e := range allEvents {
309+ fmt .Fprintf (tw , "%s\t %s\t %s\t %s\t %s\n " , e .CalendarID , e .Id , eventStart (e .Event ), eventEnd (e .Event ), e .Summary )
310+ }
311+ _ = tw .Flush ()
312+
313+ return nil
314+ }
315+
316+ func sortEventsByStartTime (events []* eventWithCalendar ) {
317+ // Simple insertion sort since we expect relatively small lists
318+ for i := 1 ; i < len (events ); i ++ {
319+ key := events [i ]
320+ keyStart := eventStart (key .Event )
321+ j := i - 1
322+ for j >= 0 && eventStart (events [j ].Event ) > keyStart {
323+ events [j + 1 ] = events [j ]
324+ j --
325+ }
326+ events [j + 1 ] = key
327+ }
328+ }
329+
209330func newCalendarEventCmd (flags * rootFlags ) * cobra.Command {
210331 return & cobra.Command {
211332 Use : "event <calendarId> <eventId>" ,
0 commit comments