aboutsummaryrefslogtreecommitdiff
Commit message (Collapse)AuthorAgeFilesLines
* chore: gitignore editor backup filesHEADmainCraig Jennings9 days1-0/+1
|
* chore: track inbox directory, ignore its contentsCraig Jennings9 days2-0/+4
|
* feat: support t for auto-detect via geolocation in wttrin-favorite-locationCraig Jennings2026-05-053-33/+270
| | | | | | | | | | | | | | | | | | Completes the three-mode configuration the favorite-location feature was always meant to have: - nil — disabled (default; unchanged) - a string — explicit location (unchanged) - t — auto-detect via IP geolocation (NEW) When the user sets `wttrin-favorite-location` to t, wttrin runs the geolocation lookup once on first use and caches the result for the session. Subsequent reads return the cached string. The lookup happens in the background via the existing `wttrin-geolocation-detect`, so Emacs startup is never blocked. I added two private state vars (`wttrin--resolved-favorite-location`, `wttrin--favorite-location-pending`) and a resolver `wttrin--resolve-favorite-location` that maps the three modes onto a returned string or nil. When t is set and the cache is empty, the resolver kicks off the lookup and returns nil for that call — the next consumer tick after the callback completes gets the cached string. The pending flag prevents duplicate concurrent lookups when several consumers ask during the resolution window. Five consumer call sites now go through the resolver instead of reading `wttrin-favorite-location` directly: `wttrin--mode-line-fetch-weather`, `wttrin-mode-line-click`, `wttrin-mode-line-force-refresh`, `wttrin--buffer-cache-refresh`, and `wttrin--mode-line-start`. Two display sites (the placeholder and error tooltips) use a new `wttrin--favorite-location-display-name` helper that returns "current location" while a t-mode lookup is pending, instead of showing the literal `t` to the user. Tests cover the resolver across all three modes, including the pending state, the duplicate-suppression behavior, and detection-failure retry. Existing consumer tests stay green because the resolver returns the bound string unchanged when the variable is a string. One care: the test file requires wttrin-geolocation up front so cl-letf mocks of `wttrin-geolocation-detect` aren't undone by the resolver's lazy require — without that, the first run hit ipapi.co for real. README documents the new mode under "Setting the Favorite Location from IP Geolocation".
* feat: add wttrin-display-options for wttr.in flag customization (closes #3)Craig Jennings2026-05-054-1/+81
| | | | | | | | | | | | wttr.in accepts single-character flags appended to the URL that control what the report looks like — no Follow line (F), narrow output (n), quiet mode (q), forecast horizon (0/1/2), console-glyph mode (d), and so on. Until now wttrin always used the same default report shape with no way to opt into these. Added a `wttrin-display-options` defcustom that takes a string of concatenated flags, e.g. "0Fq" for current weather only with no Follow line and no header. The flags get appended to every request via `wttrin--build-url`. The defcustom defaults to nil so existing users see no change. I excluded `A` and `T` from the recommended set in the docstring since wttrin needs ANSI output for the xterm-color rendering to produce the colored glyphs. The user could still pass them, but the docstring nudges them away. Tests cover the normal cases (single, multi-flag, with and without unit system), the boundaries (nil and empty string both leave the URL unchanged from baseline, single character works), and a sanity check that the new flags slot in after the always-on `A`. Existing build-url tests stay green because they don't bind the new variable, and the default is nil. Also added `.claude/` to .gitignore — the scheduled-tasks lockfile from local wakeup scheduling shouldn't be tracked.
* fix(ci): rewrite mode-init-order test and retry deps installCraig Jennings2026-05-052-45/+83
| | | | | | | | | | | | | | | | | | | | | | | | | | Two CI failures from the first run, neither a real bug in production code. The Emacs-snapshot job failed on `test-wttrin-mode-initialization-order-normal-mode-before-buffer-local-vars-calls-mode-first`. The original test mocked the `set' primitive to detect when `xterm-color--state' was first set. That worked on the byte-code path some older Emacs versions used, but `setq-local' doesn't go through the `set' function on Emacs master, so the mock never fired and the assertion read nil. The test was already brittle in isolation locally too. Rewrote the test to use `advice-add :before' on `wttrin-mode' and `make-local-variable'. Both are ordinary advisable functions, and `make-local-variable' is on the code path for every form that defines a buffer-local binding (`setq-local', `defvar-local', etc.) so the observation holds across Emacs versions. Renamed the test to drop "calls-mode-first" and use "mode-runs-before-xterm-color-state-binding" since that's what the new advice actually observes. The Emacs 26.3 job failed with a transient DNS error from elpa.gnu.org during `make deps'. Wrapped the install step in a 3-attempt retry with a 15-second backoff so a runner-side network blip doesn't fail the build. Applied to all three jobs (test, lint, coverage) since they all hit the same archives.
* docs: add CI and Coveralls badges to READMECraig Jennings2026-05-051-0/+2
| | | | Both badges point at the GitHub mirror, which is where the workflow runs and where the coverage gets reported. The CI badge reflects the latest run on `main`. The Coveralls badge tracks the most recent coverage upload from that branch.
* ci: upload coverage to CoverallsCraig Jennings2026-05-051-0/+9
| | | | | | Added a step to the coverage job that uploads `.coverage/simplecov.json` to Coveralls via `coverallsapp/github-action@v2`. The token is read from the `COVERALLS_REPO_TOKEN` repo secret. The step is set to `continue-on-error: true` so a Coveralls outage doesn't block the build, and the artifact upload stays in place as a fallback for debugging. `run-coverage-file.el` is unchanged. Undercover still produces simplecov JSON locally and on CI; the action handles the upload to coveralls.io with the right CI metadata.
* ci: add github actions for tests, lint, and coverageCraig Jennings2026-05-052-0/+150
| | | | | | | | Tests run across an Emacs version matrix (26.3, 27.2, 28.2, 29.4, snapshot) on every push to main and every PR. Lint and coverage run once each on the latest stable Emacs. The coverage job runs `make coverage`, prints the per-file and overall percentages via `scripts/coverage-summary.py`, and uploads the simplecov JSON as a build artifact (30-day retention). I'm leaving the artifact-only path in place for now and we'll wire up Coveralls in a follow-up once the repo is registered there. The matrix floor is 26.3 even though Package-Requires says 24.4. The setup-emacs action doesn't reliably support 24.x or early 25.x anymore, and the recent if-let find shows we hadn't actually been testing the stated minimum. Honest CI floor here is more useful than an aspirational one.
* refactor: rename debug-wttrin-* commands to wttrin-debug-* with obsolete aliasesCraig Jennings2026-05-057-82/+150
| | | | | | | | | | | | | | | | The four interactive commands in `wttrin-debug.el` used `debug-wttrin-` as their prefix instead of the package's `wttrin-debug-` prefix. package-lint flags this as a convention violation, and it makes M-x discovery slightly less consistent for users. Renamed: - `debug-wttrin-show-raw` -> `wttrin-debug-show-raw` - `debug-wttrin-enable` -> `wttrin-debug-enable` - `debug-wttrin-disable` -> `wttrin-debug-disable` - `debug-wttrin-mode-line` -> `wttrin-debug-mode-line` The old names stay available as `define-obsolete-function-alias` entries marked since 0.4.0, so anyone with a keybinding or `(call-interactively 'debug-wttrin-enable)` in their config keeps working. The byte-compiler will emit an obsolescence warning to nudge migration. Aliases will be removed in a future release. Internal caller `wttrin--debug-mode-line-info` now invokes the new name. Test files renamed to match (`test-debug-wttrin-*.el` -> `test-wttrin-debug-*.el`); inside each, ert-deftest names and function calls were updated. Added `tests/test-wttrin-debug-aliases.el` to verify each old name resolves via `indirect-function` to the new name and carries `byte-obsolete-info` with the expected target and "0.4.0" version.
* fix: drop if-let and personal-config reference in debug-wttrin-mode-lineCraig Jennings2026-05-051-9/+6
| | | | | | `if-let` requires Emacs 25.1, but the package declares (emacs "24.4") in Package-Requires. Replaced with `let` + `if` so the debug module loads on the stated minimum. Also dropped the `cj/modeline-major-mode` branch. That symbol is from my personal Emacs config, so the conditional was effectively dead code for anyone else and a confusing reference in a published package. The diagnostic now always shows the formatted mode-name, which is useful for everyone.
* test: cover wttrin-debug.el and expand lint to all source filesCraig Jennings2026-05-058-16/+417
| | | | | | | | | | | | I added 24 unit tests across six new files for wttrin-debug.el. They cover enable/disable, the debug-log writer, clear-log, show-log, and the mode-line diagnostic dump. That lifts wttrin-debug.el coverage from 27% to 95%, and overall coverage from 84% to 94%. Each function gets Normal / Boundary / Error categories where applicable. Globals like `wttrin-debug` and `wttrin--debug-log` are isolated per test with let-bindings. The dynamic-scope rebinding restores state cleanly at exit. I expanded the `lint` target to run on all three source files instead of just `wttrin.el`. Checkdoc and elisp-lint run on every file. Package-lint stays scoped to `wttrin.el` because the others aren't standalone packages. The tricky bit: `elisp-lint-file` re-runs package-lint internally as one of its validators. So the explicit guard alone wasn't enough. The fix binds `elisp-lint-ignored-validators` to include "package-lint" for the secondaries, which suppresses the re-run at the validator level. I also added `*-autoloads.el` to .gitignore. Eask generates `emacs-wttrin-autoloads.el` during install, and it shouldn't be tracked. I skipped one function: `wttrin--debug-mode-line-info` is a one-line dispatcher to `debug-wttrin-mode-line`. Testing it would assert the dispatch happened, which only tests Emacs.
* build: switch Makefile to eask, wire up undercover coverageCraig Jennings2026-05-054-79/+196
| | | | | | | | | | I wanted a coverage number, so I added an Eask file declaring the runtime dep (xterm-color) plus three dev deps (undercover, package-lint, elisp-lint). The Makefile now runs every test and lint recipe through `eask emacs`. That drops the hand-rolled `(require 'package)` + `add-to-list 'package-archives` boilerplate that was duplicated across six recipes. I added a `make deps` target that runs `eask install-deps --dev`. I also added a `make coverage` target that loads `tests/run-coverage-file.el` before each unit-test file. Undercover instruments the three source files first, then the test loads pick up the instrumented copy. Per-file results merge into `.coverage/simplecov.json` in simplecov format. I expanded `validate-parens` and `compile` to cover all three source files instead of just `wttrin.el`. Lint stays scoped to the main file for now. Coverage right now is 84% overall: wttrin.el 92%, wttrin-geolocation.el 100%, wttrin-debug.el 27%. The debug module is low because only the integration test exercises it. The coverage loop runs unit tests only.
* chore: untrack .stignoreCraig Jennings2026-04-262-1/+1
| | | | | | Stop tracking the Syncthing ignore file. It's local-machine config, not project content. Add it to .gitignore so the file stays put locally without showing up in git status.
* test: cover wttrin-geolocation internal helpersCraig Jennings2026-04-261-0/+187
| | | | | | | | | | | | | Four pure helpers in wttrin-geolocation.el were exercised only indirectly through the parser tests: --decode-json, --format-city-region, --lookup-provider, and --extract-body. None of them had direct unit coverage. Edge cases like an empty JSON object, a missing-vs-empty city field, an unknown provider symbol, or a missing HTTP body separator weren't locked. The new file groups all four functions together. Each gets Normal, Boundary, and Error cases per testing.md. Highlights: - --decode-json: distinguishes nil input, empty string, and malformed JSON, all of which return nil for different reasons. - --format-city-region: separates "missing key" from "empty string" since the predicate `(and (stringp city) (> (length city) 0) ...)` short-circuits on either. - --lookup-provider: tests two of the three built-ins plus a `let`-bound synthetic provider, locking the documented extension point on `wttrin-geolocation--providers`. - --extract-body: real UTF-8 bytes inserted into a temp buffer (mirroring what `url-retrieve` delivers) verify the decoding path. 4xx, 5xx, and missing-separator paths each get their own test. 21 new tests, all green on first run since they characterize existing behavior.
* docs: explain mode-line state and update flowCraig Jennings2026-04-261-0/+20
| | | | | | Four variables hold the mode-line's runtime state: the cache, the rendered string, the stale-render flag, and the refresh timer. They get updated in a specific order across three different functions. Anyone reading `wttrin--mode-line-tooltip` for the first time hits a clever bit on every hover: the tooltip re-evaluates staleness and triggers a re-render of the icon if it flipped. Without a comment that ties this to the rest of the update flow, you have to trace through three other functions to understand why. The new comment block above the defvars lays out the order and the hover-driven re-render in one place, so future readers don't have to reconstruct it from the call graph.
* refactor: extract wttrin--mode-line-extract-emoji helperCraig Jennings2026-04-262-4/+50
| | | | | | | | The regex that pulls the emoji character out of a wttr.in mode-line response was inlined inside `wttrin--mode-line-update-display`, mixed in with the render logic. Six tests of the parser couldn't be written without invoking the whole render path. The new pure helper takes the weather string, runs the regex, and returns either the first non-whitespace character after the colon or "?" as a placeholder. The format-explanation comment that used to sit above the inline code is gone now that the same explanation lives in the helper's docstring. There's no risk of comment and code drifting apart. Six tests cover Normal (typical response, different emoji), Boundary (no whitespace after colon, multiple whitespace chars), and Error (no colon, empty string).
* refactor: extract wttrin--mode-line-stale-p helperCraig Jennings2026-04-262-5/+49
| | | | | | | | The staleness check `(> age (* 2 wttrin-mode-line-refresh-interval))` lived in two places, `wttrin--mode-line-tooltip` and `wttrin--mode-line-update-display`, along with the four-line preamble that read the timestamp out of the cache cons and computed age. Centralizing the rule in a single helper means the threshold lives in one spot. That makes it easy to add a `wttrin-mode-line-staleness-threshold` defcustom later if the magic 2× ever needs to be tunable. The helper takes a cache entry (or nil) and returns t/nil. Five new tests cover Normal (fresh, stale) and Boundary (just below the threshold, just past, nil entry). The boundary tests use 199s and 201s against a 100s refresh interval to lock the strict `>` semantics with comfortable float-time margins. In `wttrin--mode-line-update-display` the refactor also drops two locals (`timestamp` and `age`) that were no longer used after the helper call replaced the inline calculation. Behavior is unchanged at both call sites.
* bump version to 0.3.2v0.3.2Craig Jennings2026-04-261-1/+1
|
* fix: omit :foreground from emoji icon face when no color providedCraig Jennings2026-04-261-4/+7
| | | | | | The font branch of wttrin--make-emoji-icon built its face plist with `:foreground foreground` even when foreground was nil, producing a literal `(:family ... :height 1.0 :foreground nil)`. The mode-line redisplays many times per second, and Emacs validates faces on every redisplay. A single fresh-cache state produced hundreds of "Invalid face attribute :foreground nil" warnings in *Messages*. The bug's been live since 2026-02-21 (b74b98f). The 130bbc07 helper extraction kept it in place. Switch to backquote splicing so the :foreground key is included only when foreground is non-nil. Behavior is identical on the colored path. On the nil path the emoji renders with the default mode-line color, the same visible result as before, without the warning flood.
* test: regression lock for nil :foreground in --make-emoji-iconCraig Jennings2026-04-261-0/+11
| | | | | | When wttrin-mode-line-emoji-font is set and the cache is fresh, --make-emoji-icon was emitting a face plist of the form (:family ... :height 1.0 :foreground nil). Emacs validates faces on every redisplay, so a single fresh-cache state produced hundreds of "Invalid face attribute :foreground nil" warnings in *Messages*. The new boundary test asserts the face plist omits :foreground entirely when the caller passes nil. The assertion uses plist-member, not plist-get. plist-get returns nil for both a missing key and a present key bound to nil. That's the exact distinction Emacs's redisplay validator cares about.
* feat: add IP geolocation command for setting wttrin-favorite-locationCraig Jennings2026-04-228-0/+751
| | | | | | | | | | | | 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.
* restructure: move docs/ to .ai/ + sync latest templateCraig Jennings2026-04-201-1/+1
| | | | | Per claude-templates c36fd14. Claude tooling moves to hidden .ai/; project-level docs/ reserved for real documentation.
* add TESTING.org test suite referenceCraig Jennings2026-04-041-0/+265
| | | | | | Quick-start commands, full Makefile target table, writing guide with file template and naming conventions, testutil-wttrin.el API docs, key patterns, and test inventory.
* bump version to 0.3.1v0.3.1Craig Jennings2026-04-041-1/+1
|
* fix: weather ASCII art wraps when window is narrowCraig Jennings2026-04-042-0/+14
| | | | | Enable truncate-lines in wttrin-mode so the fixed-width weather art clips at the window edge instead of wrapping and breaking the layout.
* fix: weather buffer shows location in lowercaseCraig Jennings2026-04-042-0/+47
| | | | | | wttr.in returns "Weather report: new orleans, la" regardless of query casing. Replace the lowercase location on the header line with the user's original string after rendering.
* feat: specific error messages for fetch failuresCraig Jennings2026-04-0411-63/+466
| | | | | | | | | | | | | | Add HTTP status code checking (wttrin--extract-http-status) and pass error descriptions through the callback chain so users see "Location not found (HTTP 404)" or "Network error — check your connection" instead of the generic "Perhaps the location was misspelled?" for every failure. Also fix pre-existing bug where the condition-case error handler in extract-response-body killed an unrelated buffer after unwind-protect already cleaned up. 330 tests (was 307), all passing.
* bump version to 0.3.0v0.3.0Craig Jennings2026-04-041-1/+1
| | | | | | Dynamic mode-line tooltip, staleness dimming, location casing fix, debug guard refactor, expanded test suite (307 tests), and multiple bug fixes since 0.2.3.
* fix: clean byte-compilation warningsCraig Jennings2026-04-042-2/+3
| | | | | | | Move define-obsolete-variable-alias before its referent defcustom to fix "alias should be declared before its referent" warning. Add defvar for wttrin--force-refresh in wttrin-debug.el so the byte-compiler knows the dynamic variable is intentional.
* doc: note wttr.in update frequency in refresh interval docstringsCraig Jennings2026-04-041-2/+5
| | | | | | wttr.in updates its data roughly every 10 minutes (max-age=600). Add a note to both refresh interval defcustoms so users know not to poll more aggressively than the service can provide.
* doc: tighten README prose, remove AI writing patternsCraig Jennings2026-04-041-30/+15
| | | | | | | Rewrite sections that read like generated text: replace clinical descriptions with conversational language matching the existing voice, cut padding phrases ("proactively", "several aspects", "what's happening"), and trim the debug section down to essentials.
* doc: update README with missing features, fix stale contentCraig Jennings2026-04-041-15/+20
| | | | | | | | | | Add: staleness display in weather buffer, stale mode-line dimming, wttrin-clear-cache command, wttrin-mode-line-startup-delay option, minimum Emacs version (24.4). Fix: font height default was listed as 110 (actually 130), debug output example didn't match current log format, manual debug setup section was a duplicate of the use-package section.
* doc: improve source comments for senior developer audienceCraig Jennings2026-04-042-29/+26
| | | | | | | | | | Remove obvious comments that restate what the code does ("save debug data if enabled", "temporarily allow editing", "align buffer to top"). Add comments explaining non-obvious decisions: why risky-local-variable is needed, why user-agent is curl, what wttr.in format codes mean, what the emoji extraction regex matches, and why after-init-time matters. Fix stale docstrings that no longer match the no-op stub pattern.
* fix: debug-wttrin-show-raw serves cached data instead of fetchingCraig Jennings2026-04-042-4/+23
| | | | | | A debug command should show what the API currently returns, not a cached copy. Bind wttrin--force-refresh to t so the fetch always bypasses the cache.
* fix: emoji dimming can disagree with tooltip stalenessCraig Jennings2026-04-042-0/+36
| | | | | | | | | | The emoji face (dimmed/normal) was frozen at the last update-display call, but the tooltip computes staleness dynamically. Between refreshes, data could cross the stale threshold — tooltip says "Stale" while the emoji is still normal. Track the rendered staleness state. When the tooltip detects a transition, trigger a re-render so the emoji dimming matches.
* fix: cache timestamp reflects request time, not response timeCraig Jennings2026-04-042-3/+30
| | | | | | | float-time was captured in the outer let* before the async fetch. The callback used this stale value, making cache entries appear slightly older than they are. Move the float-time call into the callback so the timestamp reflects when the data actually arrived.
* fix: validate-weather-data corrupts match dataCraig Jennings2026-04-042-1/+12
| | | | | string-match modifies global match data as a side effect. A predicate should not do this. Use string-match-p instead.
* fix: mode-line tooltip always shows "Updated just now"Craig Jennings2026-04-043-16/+204
| | | | | | | | | | | The tooltip was a static string computed at fetch time. Since every successful fetch sets the cache timestamp to now and immediately renders the tooltip, it was always "just now". Extract wttrin--mode-line-tooltip as a named function that computes age from the cache at call time. Set help-echo to this function so Emacs invokes it on hover, producing an accurate age like "Updated 12 minutes ago".
* fix: mode-line tooltip shows location in lowercaseCraig Jennings2026-04-042-1/+95
| | | | | | | wttr.in's %l format returns locations in lowercase (e.g., "new orleans, la") regardless of the query casing. Replace the API's location prefix with the user's original wttrin-favorite-location string at cache time so tooltips display what the user expects.
* doc: update copyright years to 2026 and add missing author fieldCraig Jennings2026-04-0437-37/+38
| | | | | Update copyright headers across all 37 .el files to include 2026. Add missing Author field to testutil-wttrin.el for consistency.
* refactor: remove malformed autoload cookie for risky-local-variableCraig Jennings2026-04-041-1/+0
| | | | | | The ;;;###autoload(put ...) form on the same line was never processed by the autoload generator. The actual (put ...) call on the next line handles this at load time. Remove the dead cookie.
* refactor: extract mode-line icon and string helpersCraig Jennings2026-04-042-40/+160
| | | | | | | | Add wttrin--make-emoji-icon and wttrin--set-mode-line-string to eliminate three near-identical propertize blocks across update-placeholder-error, set-placeholder, and update-display. Reduces wttrin--mode-line-update-display from 40 lines to 25.
* refactor: replace debug guard blocks with self-guarding no-op stubsCraig Jennings2026-04-041-62/+43
| | | | | | | | | Define wttrin--debug-log and wttrin--debug-mode-line-info as no-op stubs in wttrin.el that get overridden when wttrin-debug.el loads. Remove all 24 (when (featurep 'wttrin-debug) ...) guard blocks. Reduces cyclomatic complexity across 12 functions and eliminates visual clutter without changing behavior.
* refactor: remove dead wttrin-exit functionCraig Jennings2026-04-041-5/+0
| | | | | Never called anywhere. The 'q' keybinding in wttrin-mode inherits quit-window from special-mode, making this function redundant.
* fix: debug-wttrin-show-raw broken by async API changeCraig Jennings2026-04-042-13/+120
| | | | | | | debug-wttrin-show-raw called wttrin--get-cached-or-fetch with 1 arg, but the function now requires 2 (location + callback) since the async refactor. Rewrote to use the callback pattern. Also handles nil response gracefully.
* test: add 50 tests for untested functions; fix nil crash in save-debug-dataCraig Jennings2026-04-0412-4/+1172
| | | | | | | | | | | | | | | | | Add 11 new test files covering wttrin--save-debug-data, wttrin--buffer-cache-refresh, wttrin--mode-line-stop, wttrin--mode-line-start, wttrin-query, wttrin-requery-force, wttrin-mode-line-click, wttrin-mode-line-force-refresh, wttrin-fetch-raw-string, wttrin-clear-cache, and wttrin-requery. Fix bug in wttrin--save-debug-data where nil raw-string caused (insert nil) crash — reachable when debug mode is on and fetch fails. Refactor wttrin-requery: extract wttrin--requery-location so the core kill-buffer-and-query logic is testable without mocking completing-read. 267 tests total (was 217), all passing.
* feat: unified cache and staleness handling for mode-line and bufferCraig Jennings2026-02-219-247/+479
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Replace TTL-based cache invalidation with proactive scheduled refresh. Both mode-line and buffer systems now follow: timer refreshes cache, display reads from cache, staleness indicated when data is old. Phase 1 - Mode-line cache formalization + staleness display: - Replace wttrin--mode-line-tooltip-data with wttrin--mode-line-cache as (timestamp . data) cons cell matching buffer cache pattern - Add wttrin--format-age helper for human-readable age strings - Rewrite wttrin--mode-line-update-display to take no arguments, read from cache, compute staleness (age > 2x refresh interval), dim emoji gray when stale, show staleness info in tooltip - Rewrite wttrin--mode-line-fetch-weather to write cache on success, show stale display on failure with cache, error placeholder without - Add wttrin--mode-line-update-placeholder-error for first-launch failure Phase 2 - Remove TTL, add proactive buffer refresh: - Rename wttrin-cache-ttl to wttrin-refresh-interval (default 3600s) with define-obsolete-variable-alias for backward compatibility - Change wttrin-mode-line-refresh-interval default from 900 to 3600 - Remove TTL check from wttrin--get-cached-or-fetch; serve cached data regardless of age, background timer keeps it fresh - Add buffer refresh timer (wttrin--buffer-cache-refresh) Phase 3 - Buffer staleness display: - Add wttrin--format-staleness-header for buffer age display - Insert staleness line in wttrin--display-weather before instructions Phase 4 - Cleanup: - Remove all references to wttrin--mode-line-tooltip-data - Update README.org cache settings and mode-line documentation - Update tests for new API (198 tests across 21 files, all passing)
* feat: mode-line: show hourglass placeholder before first weather fetchCraig Jennings2026-02-202-0/+86
| | | | | | Display ⏳ with "Fetching weather..." tooltip immediately when mode-line mode starts, so the user sees wttrin is active before the first API response arrives.
* fix: mode-line: validate API response before updating displayCraig Jennings2026-02-202-4/+244
| | | | | | Reject empty or malformed wttr.in responses to prevent blank icon and tooltip. Fix tooltip lambda to treat empty string as falsy. Add debug logging for nil-location and invalid-response paths.
* doc: tests: update README-DEBUG-TESTS.org with renamed integration test fileCraig Jennings2026-02-171-0/+83
| | | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>