webbee 0.3.45__tar.gz → 0.3.47__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. {webbee-0.3.45 → webbee-0.3.47}/CHANGELOG.md +42 -0
  2. {webbee-0.3.45 → webbee-0.3.47}/PKG-INFO +1 -1
  3. {webbee-0.3.45 → webbee-0.3.47}/pyproject.toml +1 -1
  4. webbee-0.3.47/src/webbee/__init__.py +1 -0
  5. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/coding_context.py +24 -1
  6. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/selection.py +20 -2
  7. {webbee-0.3.45 → webbee-0.3.47}/tests/test_coding_context.py +12 -0
  8. {webbee-0.3.45 → webbee-0.3.47}/tests/test_session.py +4 -1
  9. {webbee-0.3.45 → webbee-0.3.47}/tests/test_tui.py +36 -0
  10. webbee-0.3.45/src/webbee/__init__.py +0 -1
  11. {webbee-0.3.45 → webbee-0.3.47}/.github/workflows/publish.yml +0 -0
  12. {webbee-0.3.45 → webbee-0.3.47}/.gitignore +0 -0
  13. {webbee-0.3.45 → webbee-0.3.47}/LICENSE +0 -0
  14. {webbee-0.3.45 → webbee-0.3.47}/README.md +0 -0
  15. {webbee-0.3.45 → webbee-0.3.47}/install.sh +0 -0
  16. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/account.py +0 -0
  17. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/active_sessions.py +0 -0
  18. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/banner_art.py +0 -0
  19. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/boot.py +0 -0
  20. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/checkpoints.py +0 -0
  21. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/cli.py +0 -0
  22. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/clipboard.py +0 -0
  23. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/clipboard_read.py +0 -0
  24. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/commands.py +0 -0
  25. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/config.py +0 -0
  26. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/consent.py +0 -0
  27. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/details.py +0 -0
  28. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/events.py +0 -0
  29. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/frames.py +0 -0
  30. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/home.py +0 -0
  31. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/home_view.py +0 -0
  32. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/http.py +0 -0
  33. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/instance_lock.py +0 -0
  34. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/intel/__init__.py +0 -0
  35. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/intel/chunker.py +0 -0
  36. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/intel/embed.py +0 -0
  37. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/intel/graph.py +0 -0
  38. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/intel/indexer.py +0 -0
  39. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/intel/models.py +0 -0
  40. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/intel/query.py +0 -0
  41. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/intel/service.py +0 -0
  42. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/intel/store.py +0 -0
  43. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/intel/vectors.py +0 -0
  44. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/intel/watch.py +0 -0
  45. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/mode_store.py +0 -0
  46. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/newtab_mode.py +0 -0
  47. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/output_pane.py +0 -0
  48. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/queue_panel.py +0 -0
  49. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/reflow.py +0 -0
  50. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/remote.py +0 -0
  51. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/render.py +0 -0
  52. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/repl.py +0 -0
  53. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/repo.py +0 -0
  54. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/session.py +0 -0
  55. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/sessions.py +0 -0
  56. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/sizing.py +0 -0
  57. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/slots.py +0 -0
  58. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/steer.py +0 -0
  59. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/stream.py +0 -0
  60. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/tab_store.py +0 -0
  61. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/tabs.py +0 -0
  62. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/thread.py +0 -0
  63. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/tier_store.py +0 -0
  64. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/todo_panel.py +0 -0
  65. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/tokens.py +0 -0
  66. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/tools.py +0 -0
  67. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/tui.py +0 -0
  68. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/update.py +0 -0
  69. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/urlopen.py +0 -0
  70. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/wallet.py +0 -0
  71. {webbee-0.3.45 → webbee-0.3.47}/src/webbee/worktrees.py +0 -0
  72. {webbee-0.3.45 → webbee-0.3.47}/tests/__init__.py +0 -0
  73. {webbee-0.3.45 → webbee-0.3.47}/tests/conftest.py +0 -0
  74. {webbee-0.3.45 → webbee-0.3.47}/tests/test_account.py +0 -0
  75. {webbee-0.3.45 → webbee-0.3.47}/tests/test_active_sessions.py +0 -0
  76. {webbee-0.3.45 → webbee-0.3.47}/tests/test_audit_2026_07_25_findings.py +0 -0
  77. {webbee-0.3.45 → webbee-0.3.47}/tests/test_checkpoints.py +0 -0
  78. {webbee-0.3.45 → webbee-0.3.47}/tests/test_cli.py +0 -0
  79. {webbee-0.3.45 → webbee-0.3.47}/tests/test_clipboard.py +0 -0
  80. {webbee-0.3.45 → webbee-0.3.47}/tests/test_clipboard_read.py +0 -0
  81. {webbee-0.3.45 → webbee-0.3.47}/tests/test_commands.py +0 -0
  82. {webbee-0.3.45 → webbee-0.3.47}/tests/test_config.py +0 -0
  83. {webbee-0.3.45 → webbee-0.3.47}/tests/test_cpc_contract_stable.py +0 -0
  84. {webbee-0.3.45 → webbee-0.3.47}/tests/test_details.py +0 -0
  85. {webbee-0.3.45 → webbee-0.3.47}/tests/test_events.py +0 -0
  86. {webbee-0.3.45 → webbee-0.3.47}/tests/test_freeze_fix.py +0 -0
  87. {webbee-0.3.45 → webbee-0.3.47}/tests/test_home.py +0 -0
  88. {webbee-0.3.45 → webbee-0.3.47}/tests/test_home_view.py +0 -0
  89. {webbee-0.3.45 → webbee-0.3.47}/tests/test_instance_lock.py +0 -0
  90. {webbee-0.3.45 → webbee-0.3.47}/tests/test_intel_chunker.py +0 -0
  91. {webbee-0.3.45 → webbee-0.3.47}/tests/test_intel_embed.py +0 -0
  92. {webbee-0.3.45 → webbee-0.3.47}/tests/test_intel_graph.py +0 -0
  93. {webbee-0.3.45 → webbee-0.3.47}/tests/test_intel_indexer.py +0 -0
  94. {webbee-0.3.45 → webbee-0.3.47}/tests/test_intel_no_numpy.py +0 -0
  95. {webbee-0.3.45 → webbee-0.3.47}/tests/test_intel_query.py +0 -0
  96. {webbee-0.3.45 → webbee-0.3.47}/tests/test_intel_service.py +0 -0
  97. {webbee-0.3.45 → webbee-0.3.47}/tests/test_intel_store.py +0 -0
  98. {webbee-0.3.45 → webbee-0.3.47}/tests/test_intel_vectors.py +0 -0
  99. {webbee-0.3.45 → webbee-0.3.47}/tests/test_intel_watch.py +0 -0
  100. {webbee-0.3.45 → webbee-0.3.47}/tests/test_marathon.py +0 -0
  101. {webbee-0.3.45 → webbee-0.3.47}/tests/test_mode_store.py +0 -0
  102. {webbee-0.3.45 → webbee-0.3.47}/tests/test_newtab_mode.py +0 -0
  103. {webbee-0.3.45 → webbee-0.3.47}/tests/test_packaging.py +0 -0
  104. {webbee-0.3.45 → webbee-0.3.47}/tests/test_queue_manage_0337.py +0 -0
  105. {webbee-0.3.45 → webbee-0.3.47}/tests/test_reflow.py +0 -0
  106. {webbee-0.3.45 → webbee-0.3.47}/tests/test_render.py +0 -0
  107. {webbee-0.3.45 → webbee-0.3.47}/tests/test_repl.py +0 -0
  108. {webbee-0.3.45 → webbee-0.3.47}/tests/test_repo.py +0 -0
  109. {webbee-0.3.45 → webbee-0.3.47}/tests/test_sessions.py +0 -0
  110. {webbee-0.3.45 → webbee-0.3.47}/tests/test_sizing.py +0 -0
  111. {webbee-0.3.45 → webbee-0.3.47}/tests/test_slots.py +0 -0
  112. {webbee-0.3.45 → webbee-0.3.47}/tests/test_steer.py +0 -0
  113. {webbee-0.3.45 → webbee-0.3.47}/tests/test_stream.py +0 -0
  114. {webbee-0.3.45 → webbee-0.3.47}/tests/test_tab_restore_0337.py +0 -0
  115. {webbee-0.3.45 → webbee-0.3.47}/tests/test_tabs.py +0 -0
  116. {webbee-0.3.45 → webbee-0.3.47}/tests/test_terminal_ux_0336.py +0 -0
  117. {webbee-0.3.45 → webbee-0.3.47}/tests/test_thread.py +0 -0
  118. {webbee-0.3.45 → webbee-0.3.47}/tests/test_tier_store.py +0 -0
  119. {webbee-0.3.45 → webbee-0.3.47}/tests/test_todo_panel.py +0 -0
  120. {webbee-0.3.45 → webbee-0.3.47}/tests/test_tokens.py +0 -0
  121. {webbee-0.3.45 → webbee-0.3.47}/tests/test_tools.py +0 -0
  122. {webbee-0.3.45 → webbee-0.3.47}/tests/test_tui_hardening.py +0 -0
  123. {webbee-0.3.45 → webbee-0.3.47}/tests/test_update.py +0 -0
  124. {webbee-0.3.45 → webbee-0.3.47}/tests/test_update_badge_0340.py +0 -0
  125. {webbee-0.3.45 → webbee-0.3.47}/tests/test_urlopen.py +0 -0
  126. {webbee-0.3.45 → webbee-0.3.47}/tests/test_version.py +0 -0
  127. {webbee-0.3.45 → webbee-0.3.47}/tests/test_version_badge_corner.py +0 -0
  128. {webbee-0.3.45 → webbee-0.3.47}/tests/test_wallet.py +0 -0
  129. {webbee-0.3.45 → webbee-0.3.47}/tests/test_worktrees.py +0 -0
@@ -1,5 +1,47 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.47
4
+
5
+ The cloud brain now sees BOTH your machine's real clock and your configured
6
+ Imperal profile timezone on every turn -- never just one blindly trusted.
7
+
8
+ - **What changed:** every coding-context snapshot now carries `client_now`
9
+ (this machine's actual wall-clock reading, ISO 8601 with UTC offset) and
10
+ `client_tz_label` (the OS/IANA timezone name) alongside the existing
11
+ cwd/git/tree/repo_key. The kernel renders both facts side by side and
12
+ flags a drift explicitly (wrong system clock, a VM in a different zone, a
13
+ stale profile setting) instead of silently trusting either source.
14
+ - **Why:** the brain previously only knew the CONFIGURED profile timezone
15
+ server-side -- it had no way to tell if the machine actually running the
16
+ agent disagreed with that (e.g. a VM parked in UTC, a laptop with a wrong
17
+ system clock). Now it always has ground truth from both ends.
18
+ - Best-effort: any clock-read failure just omits the fields -- never blocks
19
+ a turn.
20
+
21
+ ## 0.3.46
22
+
23
+ Fixed a real jitter bug in text selection: dragging to select past the
24
+ bottom (or top) of the visible output no longer makes the pane "jump
25
+ around" instead of scrolling smoothly.
26
+
27
+ - **Root cause:** a real terminal fires MOUSE_MOVE far more often than
28
+ once while the pointer sits at the viewport edge (every pixel of hand
29
+ tremor counts as a new event) -- and EVERY one of those was scrolling
30
+ the pane immediately, at the same time the dock's own ticker
31
+ (`edge_tick`) was ALSO scrolling the same pane every 0.25s to keep the
32
+ drag going while the mouse holds still. Two independent scroll sources
33
+ racing each other on the same viewport is exactly what looked like
34
+ "the window runs back and forth" while trying to select a big chunk of
35
+ text (Valentin, live 2026-07-31).
36
+ - **Fix:** the immediate scroll now fires ONLY on the actual edge
37
+ transition (the moment the drag first reaches the edge); every
38
+ following MOUSE_MOVE at the same edge just keeps the selection armed
39
+ and leaves ALL the ongoing scrolling to the ticker's one steady 0.25s
40
+ cadence -- the exact same one-source-of-truth contract the queue/todo
41
+ panels and tab bar already use for their own edge-forwarded drags, now
42
+ applied consistently everywhere in the terminal so no two panes/panels
43
+ ever fight over the same scroll.
44
+
3
45
  ## 0.3.45
4
46
 
5
47
  Consent prompts stop being an easy-to-miss detail:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: webbee
3
- Version: 0.3.45
3
+ Version: 0.3.47
4
4
  Summary: Webbee 🐝 — the Imperal Cloud coding agent in your terminal
5
5
  Project-URL: Homepage, https://imperal.io
6
6
  Project-URL: Documentation, https://docs.imperal.io
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "webbee"
3
- version = "0.3.45"
3
+ version = "0.3.47"
4
4
  description = "Webbee 🐝 — the Imperal Cloud coding agent in your terminal"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -0,0 +1 @@
1
+ __version__ = "0.3.47"
@@ -1,9 +1,19 @@
1
1
  """Coding-context snapshot for the cloud brain (extracted verbatim from
2
2
  webbee.session): build_coding_context packages cwd/git/tree/repo identity
3
3
  (+ optional repo_profile), and detect_verify_cmd is the CLIENT-detected
4
- proof-of-done command a marathon carries in that context."""
4
+ proof-of-done command a marathon carries in that context.
5
+
6
+ client_now (2026-07-31, I-CODING-TIME-CONTRACT): the machine's OWN wall-clock
7
+ reading, captured fresh on every snapshot -- distinct from whatever timezone
8
+ the user has CONFIGURED in their Imperal profile/panel. The brain needs BOTH:
9
+ the configured timezone (what the user SET) and the actual reading on the
10
+ machine running the agent (what time it REALLY is there) so it can flag a
11
+ drift (wrong system clock, VM in a different zone, stale profile setting)
12
+ instead of silently trusting one source. Best-effort: any clock read failure
13
+ degrades to an absent key, never blocks the turn."""
5
14
  import os
6
15
  import subprocess
16
+ from datetime import datetime
7
17
 
8
18
  # Heavy dependency/build dirs the file-tree walk and the agent `grep` tool
9
19
  # must NEVER descend: they blow up walk time on real repos and (with the tree's
@@ -46,6 +56,19 @@ def build_coding_context(workspace_root: str, intel=None) -> dict:
46
56
  root = find_repo_root(cwd)
47
57
  d = {"cwd": cwd, "git": git, "tree": "\n".join(paths),
48
58
  "repo_key": compute_repo_key(root), "repo_root": root}
59
+ # I-CODING-TIME-CONTRACT: the machine's actual local wall-clock, ISO 8601
60
+ # WITH UTC offset (so the kernel can compare it against the user's
61
+ # CONFIGURED timezone without re-resolving anything) + the IANA zone name
62
+ # the OS reports, when available. Never raises -- a clock/tzdata error
63
+ # just omits the key, the kernel falls back to the configured-only view.
64
+ try:
65
+ _now_local = datetime.now().astimezone()
66
+ d["client_now"] = _now_local.isoformat(timespec="seconds")
67
+ _tzname = _now_local.tzname()
68
+ if _tzname:
69
+ d["client_tz_label"] = _tzname
70
+ except Exception:
71
+ pass
49
72
  if intel is not None and getattr(intel, "ready", False):
50
73
  try:
51
74
  d["repo_profile"] = intel.repo_profile()
@@ -87,11 +87,29 @@ def make_select_control(pane, FormattedTextControl, MouseEventType, MouseButton)
87
87
  return NotImplemented
88
88
  pane._edge_ticks = 0 # a fresh MOUSE_MOVE means the pointer isn't parked
89
89
  y = ev.position.y
90
+ # webbee-code-selection-scroll-jitter-v1: a REAL terminal fires
91
+ # MOUSE_MOVE far more often than once (every pixel of hand
92
+ # tremor while parked at the edge trying to select further) --
93
+ # scrolling immediately on EVERY one of those, on top of
94
+ # edge_tick() ALREADY scrolling the same pane every 0.25s once
95
+ # armed, stacked two independent scroll sources racing each
96
+ # other and made the viewport visibly jump/jitter instead of
97
+ # scrolling smoothly (Valentin, live 2026-07-31: "окно бегает
98
+ # туда сюда"). The immediate nudge now fires ONLY on the edge
99
+ # transition (armed 0 -> 1/-1) for snappy first-touch
100
+ # feedback; every following MOUSE_MOVE that's STILL at the
101
+ # same edge just re-affirms the arm (resets _edge_ticks above,
102
+ # so the runaway guard doesn't fire) and leaves the ONGOING
103
+ # scroll entirely to edge_tick()'s single steady cadence --
104
+ # exactly the contract forward_mouse() already uses for the
105
+ # neighbor panels.
90
106
  if y >= pane._view_h - 1:
91
- pane.scroll(3)
107
+ if pane._edge_drag != 1:
108
+ pane.scroll(3)
92
109
  pane._edge_drag = 1
93
110
  elif y <= 0:
94
- pane.scroll(-3)
111
+ if pane._edge_drag != -1:
112
+ pane.scroll(-3)
95
113
  pane._edge_drag = -1
96
114
  else:
97
115
  pane._edge_drag = 0
@@ -29,3 +29,15 @@ def test_build_coding_context_still_prunes_dotdirs(tmp_path):
29
29
  tree = build_coding_context(str(tmp_path))["tree"]
30
30
  assert "src/a.py" in tree
31
31
  assert ".secret" not in tree
32
+
33
+
34
+ def test_build_coding_context_carries_client_now(tmp_path):
35
+ # I-CODING-TIME-CONTRACT: the brain needs the machine's ACTUAL wall-clock
36
+ # reading (distinct from the user's configured profile timezone) on every
37
+ # snapshot, so it can flag drift instead of blindly trusting one source.
38
+ import re
39
+ ctx = build_coding_context(str(tmp_path))
40
+ assert "client_now" in ctx
41
+ # ISO 8601 with an explicit UTC offset (+HH:MM/-HH:MM or Z) -- the kernel
42
+ # compares this against the configured timezone without re-resolving.
43
+ assert re.match(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}$", ctx["client_now"])
@@ -51,7 +51,10 @@ def test_confirm_default_relays_raw_reply_verbatim():
51
51
  def test_build_coding_context_shape(tmp_path):
52
52
  (tmp_path / "a.txt").write_text("x")
53
53
  ctx = build_coding_context(str(tmp_path))
54
- assert set(ctx) == {"cwd", "git", "tree", "repo_key", "repo_root"}
54
+ # I-CODING-TIME-CONTRACT: client_now/client_tz_label ride every snapshot
55
+ # (best-effort -- a clock-read failure would simply omit them).
56
+ assert set(ctx) == {"cwd", "git", "tree", "repo_key", "repo_root",
57
+ "client_now", "client_tz_label"}
55
58
  assert "a.txt" in ctx["tree"]
56
59
 
57
60
 
@@ -258,6 +258,42 @@ def test_drag_at_bottom_edge_scrolls_and_grows_selection():
258
258
  assert pane._edge_drag == 0
259
259
 
260
260
 
261
+ def test_repeated_mouse_move_at_same_edge_does_not_double_scroll():
262
+ # webbee-code-selection-scroll-jitter-v1: a real terminal fires MOUSE_MOVE
263
+ # repeatedly while the pointer sits at the SAME edge (hand tremor) --
264
+ # only the FIRST one (the 0 -> armed transition) may scroll immediately;
265
+ # every following MOUSE_MOVE at the same edge must leave the offset
266
+ # alone (still armed, still selecting) and let edge_tick() do the only
267
+ # ongoing scrolling, one steady source instead of two racing.
268
+ from prompt_toolkit.data_structures import Point
269
+ from prompt_toolkit.mouse_events import MouseButton, MouseEvent, MouseEventType
270
+
271
+ from webbee.tui import OutputPane
272
+
273
+ pane = OutputPane(width=80)
274
+ pane._view_h = 10
275
+ pane._io.write("\n".join(f"line{i}" for i in range(100)))
276
+ pane._offset = 0
277
+
278
+ down = MouseEvent(position=Point(0, 5), event_type=MouseEventType.MOUSE_DOWN,
279
+ button=MouseButton.LEFT, modifiers=frozenset())
280
+ pane.control.mouse_handler(down)
281
+
282
+ move = MouseEvent(position=Point(3, 9), event_type=MouseEventType.MOUSE_MOVE,
283
+ button=MouseButton.LEFT, modifiers=frozenset())
284
+ pane.control.mouse_handler(move)
285
+ assert pane._offset == 3 and pane._edge_drag == 1 # first touch: one immediate nudge
286
+
287
+ # the pointer trembles but stays at the SAME bottom row -- must NOT scroll again.
288
+ pane.control.mouse_handler(move)
289
+ pane.control.mouse_handler(move)
290
+ assert pane._offset == 3 and pane._edge_drag == 1 # unchanged -- no double scroll
291
+
292
+ # only edge_tick() advances it further, at its own steady cadence.
293
+ pane.edge_tick()
294
+ assert pane._offset == 6
295
+
296
+
261
297
  def test_edge_drag_resets_on_mouse_up_and_top_edge_mirrors():
262
298
  from prompt_toolkit.data_structures import Point
263
299
  from prompt_toolkit.mouse_events import MouseButton, MouseEvent, MouseEventType
@@ -1 +0,0 @@
1
- __version__ = "0.3.45"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes