Skip to content

Conversation

dabrowskiw
Copy link

Hello,

I have added autocompletion of attendees in the event editor.
This works by exposing an additional configuration option "address_adapter" in the account section. The command specified there is run on startup using "bash -c" and the input is parsed as the contacts for that account. The parser (in CalendarCollection, in _contacts_update()) is written under the assumption that "address_adapter" will be "khal email | tail -n +2", however I am sure other contact managers can be forced to output in the same format, or the parser can be extended to be more intelligent.

The autocomplete (in attendeewidget.py) is using IndicativeListBox from additional_urwid_widgets (available via pip, pyproject.toml updated accordingly) to display autocomplete options and some ugly hackery to pretend that focus is still on the address line while it actually is in the list.

All tests run, and I suspect that the autogenerated configspec.rst should include the comment from khal.spec where I explained how address_adapter works - I am not sure though since I am not familiar with Sphinx and was not able to divine how the Makefile generated the configspec.rst file.

This code is not going to win any beauty contests, the best I can do is hope that only a few of those who look at it will need PTSD treatment. However, this is a development driven by need and not by too much spare time, so I am afraid that it's either "share it now" or "share it when it's cleaned up, which may well be never". If you think the usefulness of the feature outweighs the ugliness of the code, I am more than happy to contribute, but I will not be offended if you don't.

Anyways, thanks for the great tool that khal is, I very much enjoy working with it :)

# since it has only been developed with khard in mind - but other providers
# should be configurable to create the same output, or the parser could
# be extended (see _contacts_update in CalenderCollection in khalendar.py)
address_adapter = string(default=None)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What behaviour does None cause and why not default to khard email | tail -n +2?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None causes no autocompletion to be available (no address book). The idea behind not setting the default to khard email was that not everyone might have khard installed.

However, I agree that this is counterintuitive. I have committed a change that:

  • Adds an address_adapter field to the [default] section that
    • Is, by default, khard email | tail -n +2
    • Can be None, meaning "empty address book"
  • Adds the possible value "default" (which is also the default) to the address_adapter in the account section. That value causes the address_adapter from the [default] section to be used for that calendar
  • Tests whether the command from address_adapter was run successfully. If that is not the case, the effect is the same as setting address_adapter to None, i.e. the address book is assumed to be empty.

Does that make more sense?

@geier
Copy link
Member

geier commented Apr 27, 2024

Thanks for your contribution, @dabrowskiw! This sounds like a very useful feature!

Some notes:

For me, the attendee widget doesn't have a leading 'Attendee' anymore and I believe that text field should be labeled.

image

I would liket to drop the ruff commit, it adds a lot of noise which makes reviewing the PR harder. (I rebased this PR on master and dropped the ruff commit, see https://github.com/pimutils/khal/tree/rebase_pr1324 )

@JFincher42
Copy link

JFincher42 commented Sep 10, 2025

So I've been trying to use this and make it work for two days, but keep running into a breaking issue.

I forked the code and used git fetch to get the PR down. I checkout the rebase_pr1324 branch, create a venv using uv venv, then uv sync to sync the dependencies from pyproject.toml, then finally run uv run ikhal to run the app.

When I save an event (new or existing), even with no other changes, ikhal dies with the following error:

Traceback (most recent call last):
  File "/home/jon/git/khal/khal/ui/__init__.py", line 1496, in start_pane
    loop.run()
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/event_loop/main_loop.py", line 339, in run
    self._run()
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/event_loop/main_loop.py", line 441, in _run
    self.event_loop.run()
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/event_loop/select_loop.py", line 182, in run
    self._loop()
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/event_loop/select_loop.py", line 229, in _loop
    record.data()
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/display/_posix_raw_display.py", line 285, in wrapper
    return self.parse_input(event_loop, callback, self.get_available_raw_input())
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/display/_raw_display_base.py", line 488, in parse_input
    callback(decoded_codes, raw_codes)
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/event_loop/main_loop.py", line 466, in _update
    self.process_input(keys)
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/event_loop/main_loop.py", line 561, in process_input
    if handled_key := self._topmost_widget.keypress(self.screen_size, key):
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/widget/popup.py", line 143, in keypress
    return self._current_widget.keypress(size, key)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/widget/frame.py", line 517, in keypress
    return self.body.keypress((maxcol, remaining), key)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/widget/columns.py", line 1185, in keypress
    key = w.keypress(size_args[i], key)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/widget/widget.py", line 612, in keypress
    return get_delegate(self).keypress(size, key)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/widget/widget.py", line 612, in keypress
    return get_delegate(self).keypress(size, key)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/khal/ui/editor.py", line 613, in keypress
    return_value = super().keypress(size, key)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/widget/widget.py", line 612, in keypress
    return get_delegate(self).keypress(size, key)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/khal/ui/widgets.py", line 385, in keypress
    key = super().keypress(size, key)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/widget/listbox.py", line 1290, in keypress
    key = focus_widget.keypress((maxcol,), key)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/widget/columns.py", line 1185, in keypress
    key = w.keypress(size_args[i], key)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/widget/padding.py", line 407, in keypress
    return self._original_widget.keypress(maxvals, key)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/widget/widget.py", line 612, in keypress
    return get_delegate(self).keypress(size, key)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/widget/wimp.py", line 762, in keypress
    self._emit("click")
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/widget/widget.py", line 310, in _emit
    signals.emit_signal(self, name, self, *args)
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/signals.py", line 299, in emit
    result |= self._call_callback(callback, user_arg, weak_args, user_args, args)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/.venv/lib/python3.12/site-packages/urwid/signals.py", line 323, in _call_callback
    return bool(callback(*args))
                ^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/khal/ui/editor.py", line 596, in save
    self.collection.update(self.event)
  File "/home/jon/git/khal/khal/khalendar/khalendar.py", line 184, in update
    assert event.raw is not None
           ^^^^^^^^^
  File "/home/jon/git/khal/khal/khalendar/event.py", line 421, in raw
    timezone = create_timezone(tzinfo, self.start)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jon/git/khal/khal/khalendar/event.py", line 988, in create_timezone
    for one, two in iter(tz._tzinfos.items())  # type: ignore
                         ^^^^^^^^^^^
AttributeError: 'zoneinfo.ZoneInfo' object has no attribute '_tzinfos'

Switching back to the master branch ran everything flawlessly.

System is EndeavourOS (Arch distro) with the Zen kernel (6.16.5) and running Python 3.12.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants