aboutsummaryrefslogtreecommitdiff
path: root/wttrin.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-04-22 00:07:51 -0500
committerCraig Jennings <c@cjennings.net>2026-04-22 00:07:51 -0500
commit9958ec4c4396ae8435f7e1818ff383c05df47a14 (patch)
tree9835229246368cca582f669837cd2859a79c8862 /wttrin.el
parent603f70d78f771c0a14c7f312aee6da68060b5d8b (diff)
downloademacs-wttrin-9958ec4c4396ae8435f7e1818ff383c05df47a14.tar.gz
emacs-wttrin-9958ec4c4396ae8435f7e1818ff383c05df47a14.zip
feat: add IP geolocation command for setting wttrin-favorite-location
Lets users set `wttrin-favorite-location` by IP lookup instead of typing a city by hand. `M-x wttrin-set-location-from-geolocation` runs the lookup, shows the detected "City, Region" in a yes/no prompt, and on confirmation sets the variable for the session. The docstring points at `M-x customize-save-variable` for persistence across restarts. The new `wttrin-geolocation.el` module provides the provider layer. Three providers come built in: ipapi.co (the default), ipinfo.io, and ipwho.is. All three are HTTPS, need no API key, and have free tiers large enough for interactive use. The module has three layers. Pure JSON parsers handle the per-provider quirks: ipapi's `error: true` flag, ipwho.is's `success: false` flag, ipinfo's HTTP-status-only signalling. A small fetch helper extracts the HTTP body. `wttrin-geolocation-detect` wires them together and calls back with "City, Region" on success, or nil on any failure (network error, HTTP 4xx or 5xx, malformed response, rate-limit signal). Providers live in an alist keyed by symbol, with plist values for :name, :url, and :parser. To use a different provider, push an entry onto `wttrin-geolocation--providers` and select it via `wttrin-geolocation-provider`. No code change needed. README gains a subsection under Mode-line Weather Display covering the command, how to persist the result, provider selection with free-tier limits, and the accuracy caveat for VPN or mobile-hotspot users. 39 new tests across the parser layer (10 ipapi, 6 ipinfo, 6 ipwhois), fetch-and-dispatch (11), and interactive command (6). Each suite covers Normal, Boundary, and Error categories. Tests mock `url-retrieve` and `yes-or-no-p` at their boundaries and run the real extract-and-parse pipeline underneath. Test suite: 333 → 373 passing.
Diffstat (limited to 'wttrin.el')
-rw-r--r--wttrin.el34
1 files changed, 34 insertions, 0 deletions
diff --git a/wttrin.el b/wttrin.el
index 767b552..d09a64a 100644
--- a/wttrin.el
+++ b/wttrin.el
@@ -39,6 +39,10 @@
;; Declare xterm-color functions (loaded on-demand)
(declare-function xterm-color-filter "xterm-color" (string))
+;; Declare geolocation entry point (loaded on-demand by
+;; `wttrin-set-location-from-geolocation')
+(declare-function wttrin-geolocation-detect "wttrin-geolocation" (callback))
+
;; No-op stubs for debug functions (overridden when wttrin-debug.el is loaded)
(defun wttrin--debug-mode-line-info ()
"No-op stub. Replaced by `wttrin-debug' when debug mode is active."
@@ -539,6 +543,36 @@ This creates headroom to avoid frequent cleanups."
(clrhash wttrin--cache)
(message "Weather cache cleared"))
+;;;###autoload
+(defun wttrin-set-location-from-geolocation ()
+ "Detect your location via IP geolocation and set it as the favorite.
+Uses the provider named by `wttrin-geolocation-provider' to fetch
+\"City, Region\", asks for confirmation, and on yes assigns the
+result to `wttrin-favorite-location' for this session.
+
+To persist the setting across Emacs sessions, either run
+\\[customize-save-variable] on `wttrin-favorite-location', or add
+\(setq wttrin-favorite-location ...\) to your init file.
+
+IP-based geolocation can be wrong behind a VPN or a mobile hotspot.
+The confirmation prompt shows the detected location so you can
+reject inaccurate results."
+ (interactive)
+ (require 'wttrin-geolocation)
+ (message "Detecting location...")
+ (wttrin-geolocation-detect
+ (lambda (location)
+ (cond
+ ((null location)
+ (message "Could not detect location (network or provider error)"))
+ ((yes-or-no-p (format "Detected location: %s. Set as favorite? "
+ location))
+ (setq wttrin-favorite-location location)
+ (message "Set wttrin-favorite-location to: %s. Run M-x customize-save-variable to persist."
+ location))
+ (t
+ (message "Location detection cancelled"))))))
+
(defvar-local wttrin--current-location nil
"Current location displayed in this weather buffer.")