fix: khal and notmuch in path
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
import subprocess
|
import subprocess
|
||||||
import shutil
|
import shutil
|
||||||
from datetime import datetime
|
from datetime import datetime, date
|
||||||
from fabric.widgets.box import Box
|
from fabric.widgets.box import Box
|
||||||
from fabric.widgets.label import Label
|
from fabric.widgets.label import Label
|
||||||
from fabric.widgets.button import Button
|
from fabric.widgets.button import Button
|
||||||
@@ -10,6 +10,17 @@ from fabric.widgets.wayland import WaylandWindow as Window
|
|||||||
from loguru import logger
|
from loguru import logger
|
||||||
from bar.config import CALENDAR
|
from bar.config import CALENDAR
|
||||||
|
|
||||||
|
# Try to import khal as a Python library
|
||||||
|
try:
|
||||||
|
from khal.cli.main import main_khal
|
||||||
|
from khal.settings import get_config
|
||||||
|
from khal.khalendar import CalendarCollection
|
||||||
|
KHAL_AVAILABLE = True
|
||||||
|
logger.info("[Calendar] Using khal as Python library")
|
||||||
|
except ImportError:
|
||||||
|
KHAL_AVAILABLE = False
|
||||||
|
logger.info("[Calendar] khal Python library not available, falling back to subprocess")
|
||||||
|
|
||||||
|
|
||||||
class CalendarService:
|
class CalendarService:
|
||||||
def __init__(self, update_interval=300000): # 5 minutes default
|
def __init__(self, update_interval=300000): # 5 minutes default
|
||||||
@@ -64,15 +75,52 @@ class CalendarService:
|
|||||||
"""Get cached events without triggering update"""
|
"""Get cached events without triggering update"""
|
||||||
return self.events
|
return self.events
|
||||||
|
|
||||||
def update_events(self):
|
def update_events_python_api(self):
|
||||||
"""Fetch today's events from khal"""
|
"""Fetch today's events using khal Python API"""
|
||||||
# Check if calendar is enabled
|
try:
|
||||||
if not CALENDAR.get("enable", True):
|
# Get khal configuration
|
||||||
logger.info("[Calendar] Calendar is disabled in config")
|
config = get_config()
|
||||||
self.events = []
|
|
||||||
self.emit_events_changed(self.events)
|
|
||||||
return
|
|
||||||
|
|
||||||
|
# Create calendar collection
|
||||||
|
collection = CalendarCollection.from_calendars(
|
||||||
|
calendars=config['calendars'],
|
||||||
|
dbpath=config['sqlite']['path'],
|
||||||
|
locale=config['locale'],
|
||||||
|
color=config['default']['print_new'],
|
||||||
|
unicode_symbols=config['default']['unicode_symbols'],
|
||||||
|
default_calendar=config['default']['default_calendar'],
|
||||||
|
readonly=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get today's events
|
||||||
|
today = date.today()
|
||||||
|
events = collection.get_events_on(today)
|
||||||
|
|
||||||
|
# Format events to match our expected structure
|
||||||
|
formatted_events = []
|
||||||
|
for event in events:
|
||||||
|
formatted_event = {
|
||||||
|
'title': str(event.summary),
|
||||||
|
'start': event.start.strftime('%m-%d %H:%M') if hasattr(event.start, 'strftime') else '',
|
||||||
|
'end': event.end.strftime('%m-%d %H:%M') if hasattr(event.end, 'strftime') else '',
|
||||||
|
'location': str(event.location) if event.location else ''
|
||||||
|
}
|
||||||
|
formatted_events.append(formatted_event)
|
||||||
|
|
||||||
|
# Sort by start time
|
||||||
|
formatted_events.sort(key=lambda e: e.get('start', ''))
|
||||||
|
|
||||||
|
self.events = formatted_events
|
||||||
|
logger.info(f"[Calendar] Found {len(self.events)} events using Python API")
|
||||||
|
self.emit_events_changed(self.events)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"[Calendar] Error using khal Python API: {e}")
|
||||||
|
# Fall back to subprocess method
|
||||||
|
self.update_events_subprocess()
|
||||||
|
|
||||||
|
def update_events_subprocess(self):
|
||||||
|
"""Fetch today's events using khal subprocess (fallback)"""
|
||||||
# Get khal path from config
|
# Get khal path from config
|
||||||
khal_path = CALENDAR.get("khal_path", "khal")
|
khal_path = CALENDAR.get("khal_path", "khal")
|
||||||
|
|
||||||
@@ -115,56 +163,38 @@ class CalendarService:
|
|||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Filter events for today - both past and upcoming
|
self.events = all_events
|
||||||
now = datetime.now()
|
logger.info(f"[Calendar] Found {len(self.events)} events using subprocess")
|
||||||
current_time = now.strftime("%H:%M")
|
self.emit_events_changed(self.events)
|
||||||
current_date = now.strftime("%m-%d")
|
else:
|
||||||
|
self.events = []
|
||||||
past_events = []
|
|
||||||
upcoming_events = []
|
|
||||||
|
|
||||||
for event in all_events:
|
|
||||||
event_date = (
|
|
||||||
event.get("start", "").split()[0] if event.get("start") else ""
|
|
||||||
)
|
|
||||||
event_start_time = (
|
|
||||||
event.get("start", "").split()[1] if event.get("start") else ""
|
|
||||||
)
|
|
||||||
event_end_time = (
|
|
||||||
event.get("end", "").split()[1] if event.get("end") else ""
|
|
||||||
)
|
|
||||||
|
|
||||||
# Only process events from today
|
|
||||||
if event_date == current_date:
|
|
||||||
if not event_end_time: # All-day events
|
|
||||||
upcoming_events.append(event)
|
|
||||||
elif event_end_time > current_time: # Haven't ended yet
|
|
||||||
upcoming_events.append(event)
|
|
||||||
elif event_end_time <= current_time: # Already ended
|
|
||||||
past_events.append(event)
|
|
||||||
|
|
||||||
# Sort past events by start time (most recent first)
|
|
||||||
past_events.sort(key=lambda e: e.get("start", ""), reverse=True)
|
|
||||||
|
|
||||||
# Take up to 3 most recent past events and up to 5 upcoming events
|
|
||||||
selected_past = past_events[:3]
|
|
||||||
selected_upcoming = upcoming_events[:5]
|
|
||||||
|
|
||||||
# Combine: past events first, then upcoming events
|
|
||||||
self.events = selected_past + selected_upcoming
|
|
||||||
logger.info(f"[Calendar] Found {len(self.events)} upcoming events")
|
|
||||||
for i, event in enumerate(self.events):
|
|
||||||
logger.info(
|
|
||||||
f"[Calendar] Event {i+1}: {event.get('title', 'No title')} at {event.get('start', 'No time')}"
|
|
||||||
)
|
|
||||||
self.emit_events_changed(self.events)
|
self.emit_events_changed(self.events)
|
||||||
|
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
logger.error(f"[Calendar] Failed to fetch events: {e}")
|
logger.error(f"[Calendar] Failed to fetch events: {e}")
|
||||||
self.events = []
|
self.events = []
|
||||||
|
self.emit_events_changed(self.events)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[Calendar] Error processing events: {e}")
|
logger.error(f"[Calendar] Error processing events: {e}")
|
||||||
self.events = []
|
self.events = []
|
||||||
|
self.emit_events_changed(self.events)
|
||||||
|
|
||||||
|
def update_events(self):
|
||||||
|
"""Fetch today's events from khal"""
|
||||||
|
# Check if calendar is enabled
|
||||||
|
if not CALENDAR.get("enable", True):
|
||||||
|
logger.info("[Calendar] Calendar is disabled in config")
|
||||||
|
self.events = []
|
||||||
|
self.emit_events_changed(self.events)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Try Python API first, fall back to subprocess
|
||||||
|
if KHAL_AVAILABLE:
|
||||||
|
logger.info("[Calendar] Using khal Python API")
|
||||||
|
self.update_events_python_api()
|
||||||
|
else:
|
||||||
|
logger.info("[Calendar] Using khal subprocess")
|
||||||
|
self.update_events_subprocess()
|
||||||
|
|
||||||
|
|
||||||
class CalendarPopup(Window):
|
class CalendarPopup(Window):
|
||||||
|
|||||||
38
flake.nix
38
flake.nix
@@ -100,6 +100,35 @@
|
|||||||
default = { enable = false; };
|
default = { enable = false; };
|
||||||
description = "Stylix configuration passed from the stylix module";
|
description = "Stylix configuration passed from the stylix module";
|
||||||
};
|
};
|
||||||
|
calendar = {
|
||||||
|
enable = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Whether to enable the calendar widget";
|
||||||
|
};
|
||||||
|
khal_path = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "khal";
|
||||||
|
description = "Path to the khal binary";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
notmuch = {
|
||||||
|
enable = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Whether to enable the notmuch email widget";
|
||||||
|
};
|
||||||
|
notmuch_path = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "notmuch";
|
||||||
|
description = "Path to the notmuch binary";
|
||||||
|
};
|
||||||
|
emacsclient_command = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "emacsclient";
|
||||||
|
description = "Path to the emacsclient binary";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
default = {
|
default = {
|
||||||
@@ -108,6 +137,15 @@
|
|||||||
height = 40;
|
height = 40;
|
||||||
window_title.enable = true;
|
window_title.enable = true;
|
||||||
stylix.enable = false;
|
stylix.enable = false;
|
||||||
|
calendar = {
|
||||||
|
enable = true;
|
||||||
|
khal_path = "khal";
|
||||||
|
};
|
||||||
|
notmuch = {
|
||||||
|
enable = true;
|
||||||
|
notmuch_path = "notmuch";
|
||||||
|
emacsclient_command = "emacsclient";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,6 +12,9 @@
|
|||||||
wrapGAppsHook3,
|
wrapGAppsHook3,
|
||||||
playerctl,
|
playerctl,
|
||||||
webp-pixbuf-loader,
|
webp-pixbuf-loader,
|
||||||
|
notmuch,
|
||||||
|
khal,
|
||||||
|
emacs,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
|
||||||
@@ -38,6 +41,8 @@ python3Packages.buildPythonApplication {
|
|||||||
gdk-pixbuf
|
gdk-pixbuf
|
||||||
playerctl
|
playerctl
|
||||||
webp-pixbuf-loader
|
webp-pixbuf-loader
|
||||||
|
notmuch
|
||||||
|
khal
|
||||||
];
|
];
|
||||||
|
|
||||||
dependencies = with python3Packages; [
|
dependencies = with python3Packages; [
|
||||||
@@ -60,13 +65,19 @@ python3Packages.buildPythonApplication {
|
|||||||
cp scripts/launcher.py $out/bin/bar
|
cp scripts/launcher.py $out/bin/bar
|
||||||
chmod +x $out/bin/bar
|
chmod +x $out/bin/bar
|
||||||
|
|
||||||
|
|
||||||
runHook postInstall
|
runHook postInstall
|
||||||
'';
|
'';
|
||||||
|
|
||||||
preFixup = ''
|
preFixup = ''
|
||||||
makeWrapperArgs+=("''${gappsWrapperArgs[@]}")
|
makeWrapperArgs+=("''${gappsWrapperArgs[@]}")
|
||||||
|
makeWrapperArgs+=(--prefix PATH : ${lib.makeBinPath [ khal notmuch emacs ]})
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
passthru = {
|
||||||
|
inherit khal notmuch emacs;
|
||||||
|
};
|
||||||
|
|
||||||
meta = {
|
meta = {
|
||||||
changelog = "";
|
changelog = "";
|
||||||
description = ''
|
description = ''
|
||||||
|
|||||||
Reference in New Issue
Block a user