vappman 2.2.1__tar.gz → 2.2.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: vappman
3
- Version: 2.2.1
3
+ Version: 2.2.2
4
4
  Summary: A visual wrapper for appman
5
5
  Keywords: app,installer,manager,appimages
6
6
  Author-email: Joe Defen <joedef@google.com>
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3.12
15
15
  Classifier: Programming Language :: Python :: 3.13
16
16
  Classifier: Operating System :: POSIX :: Linux
17
17
  License-File: LICENSE
18
- Requires-Dist: console-window == 2.1.3
18
+ Requires-Dist: console-window == 2.2.2
19
19
  Requires-Dist: pytest>=7 ; extra == "dev"
20
20
  Requires-Dist: pytest-cov>=5 ; extra == "dev"
21
21
  Requires-Dist: ruff>=0.6 ; extra == "dev"
@@ -32,7 +32,7 @@ classifiers = [
32
32
  "Operating System :: POSIX :: Linux"
33
33
  ]
34
34
  dependencies = [
35
- 'console-window == 2.1.3',
35
+ 'console-window == 2.2.2',
36
36
  ]
37
37
 
38
38
  [project.urls]
@@ -61,6 +61,20 @@ dev = [
61
61
  testpaths = ["tests"]
62
62
  addopts = "-ra"
63
63
 
64
+ [tool.coverage.run]
65
+ source = ["vappman"]
66
+
67
+ [tool.coverage.report]
68
+ # Set just below the measured number when the shared gate was adopted. Raise
69
+ # it as the suite grows; never lower it to make a commit pass.
70
+ fail_under = 35
71
+
72
+ [tool.bless]
73
+ # The default is the pair, written out here so the branch model is visible
74
+ # where the rest of this project's identity lives. `publish` aligns `dev`
75
+ # with `main` before tagging, and pushes both.
76
+ branches = ["main", "dev"]
77
+
64
78
  [tool.ruff]
65
79
  # Keep the lint gate identical on every machine: no global/user config can
66
80
  # change which rules the gate enforces. The selection below is deliberately
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
  # -*- coding: utf-8 -*-
3
- """Semantic colour roles and the appearance preferences for vappman.
3
+ """The appearance preferences for vappman.
4
4
 
5
5
  Colour is decoration, never information. Every role degrades to an attribute
6
6
  (or to plain text) when the terminal has no colour, so the installed markers
@@ -12,69 +12,35 @@ colour numbers. console-window installs those pairs at startup and re-installs
12
12
  them whenever a theme is applied, so changing the active theme recolours the
13
13
  whole UI without an edit to any draw code.
14
14
 
15
+ The role-to-attribute mapping, the process-wide switch and the forgiving lookup
16
+ live in :mod:`console_window.appearance`, and are re-exported here. Keeping one
17
+ switch matters: the library's theme picker paints its swatches through that
18
+ layer, so a vappman-local copy would leave the picker in colour while the rest
19
+ of the UI went mono.
20
+
15
21
  ``mono`` is vappman's own no-colour pseudo-theme: console-window's
16
22
  ``dark-mono``/``light-mono`` are still colour themes, so the true monochrome
17
- appearance lives here as the :data:`MONO_ROLES` mapping. It is part of the
23
+ appearance is "colour off" rather than a library theme. It is part of the
18
24
  picker's rotation but is not a library theme.
19
25
  """
20
26
 
21
27
  import os
22
- import curses
23
28
 
24
29
  from console_window import Theme
30
+ from console_window.appearance import (
31
+ MONO_ROLES, colors_enabled, semantic_attr, set_colors_enabled,
32
+ )
33
+
34
+ # Explicit re-exports: the appearance API is read from this module by vappman.
35
+ __all__ = [
36
+ 'MONO_ROLES', 'MONO_THEME', 'appearance_choices', 'appearance_label',
37
+ 'colors_enabled', 'resolve_ui_prefs', 'semantic_attr',
38
+ 'set_colors_enabled',
39
+ ]
25
40
 
26
41
  # vappman's pseudo-theme: no colour at all, only attributes.
27
42
  MONO_THEME = 'mono'
28
43
 
29
- # Role -> attribute used when colour is off. The hierarchy is preserved with
30
- # emphasis instead of hue: destructive prompts are bold+reverse, informational
31
- # rows carry nothing (their ✔/🔒 and S/U markers already distinguish them).
32
- MONO_ROLES = {
33
- Theme.DANGER: curses.A_BOLD | curses.A_REVERSE,
34
- Theme.ERROR: curses.A_BOLD | curses.A_REVERSE,
35
- Theme.WARNING: curses.A_BOLD,
36
- Theme.SUCCESS: curses.A_BOLD,
37
- Theme.EMPHASIS: curses.A_BOLD,
38
- Theme.INFO: curses.A_NORMAL,
39
- Theme.PROGRESS: curses.A_NORMAL,
40
- Theme.OLD_SUCCESS: curses.A_NORMAL,
41
- Theme.HOTSWAP: curses.A_NORMAL,
42
- }
43
-
44
- # Process-wide switch, seeded at startup by --no-color / NO_COLOR / mono. One
45
- # terminal, so one decision.
46
- _COLORS_ENABLED = True
47
-
48
-
49
- def set_colors_enabled(enabled):
50
- """Turn semantic colour on or off for the whole process."""
51
- global _COLORS_ENABLED # pylint: disable=global-statement
52
- _COLORS_ENABLED = bool(enabled)
53
-
54
-
55
- def colors_enabled():
56
- """True while semantic roles resolve to colour pairs rather than attributes."""
57
- return _COLORS_ENABLED
58
-
59
-
60
- def semantic_attr(pair_id):
61
- """Attribute for a console-window ``Theme`` role, or plain when no colour.
62
-
63
- With colour off the role becomes an attribute from :data:`MONO_ROLES`, so
64
- the UI keeps its emphasis hierarchy on a monochrome terminal. Otherwise
65
- both ``curses.has_colors()`` and ``curses.color_pair()`` can raise
66
- ``curses.error`` before ``initscr()`` (and a failed lookup must never abort
67
- a redraw), so any failure degrades to plain text.
68
- """
69
- if not _COLORS_ENABLED:
70
- return MONO_ROLES.get(pair_id, curses.A_NORMAL)
71
- try:
72
- if not curses.has_colors():
73
- return 0
74
- return curses.color_pair(pair_id)
75
- except curses.error:
76
- return 0
77
-
78
44
 
79
45
  def appearance_choices():
80
46
  """Every appearance the picker cycles, in order.
@@ -1,3 +1,3 @@
1
1
  """vappman -- a visual wrapper for appman."""
2
2
 
3
- __version__ = "2.2.1"
3
+ __version__ = "2.2.2"
@@ -36,8 +36,8 @@ from .Prerequisites import Prerequisites
36
36
  from .VappmanListCache import AppCacheManager
37
37
  from . import AppimageDoctor
38
38
  from .Appearance import (
39
- MONO_THEME, appearance_choices, appearance_label, resolve_ui_prefs,
40
- semantic_attr, set_colors_enabled,
39
+ MONO_THEME, appearance_choices, appearance_label, colors_enabled,
40
+ resolve_ui_prefs, semantic_attr, set_colors_enabled,
41
41
  )
42
42
 
43
43
  # Screen constants
@@ -501,21 +501,39 @@ class VappmanHelpScreen(BasicHelpScreen):
501
501
  self.app.ss.push(THEMES_ST, self.app.win.pick_pos)
502
502
 
503
503
 
504
- # console-window's generic picker draws the swatches and the hint line; only
505
- # the cycle is overridden so vappman's 'mono' pseudo-theme is part of the
506
- # rotation and the process-wide colour switch follows it. Keeping the generic
507
- # draw means the preview is console-window's role set, not a vappman copy.
504
+ # Key that cycles the appearance; the picker's hint line advertises it.
505
+ THEME_CYCLE_KEY = 't'
506
+
507
+ # One dim line under the swatches. It must not explain mono: a picker entry
508
+ # named 'mono' with a monochrome preview explains itself, and the sentence
509
+ # showed under every colour theme as well.
510
+ THEME_PICKER_NOTE = 'The choice is remembered for the next run.'
511
+
512
+ # console-window paints the swatches through its appearance layer, so they
513
+ # follow the same process-wide colour switch vappman flips for 'mono': with
514
+ # colour off the picker shows the monochrome role hierarchy instead of the
515
+ # previous palette. Only the cycle and the header label are vappman's.
508
516
  _ThemePickerScreen = Theme.create_picker_screen(
509
517
  VappmanScreen,
510
- cycle_key='t',
511
- note='The last entry, mono, uses no colour at all. '
512
- 'The choice is remembered for the next run.',
518
+ cycle_key=THEME_CYCLE_KEY,
519
+ note=THEME_PICKER_NOTE,
513
520
  )
514
521
 
515
522
 
516
523
  class VappmanThemeScreen(_ThemePickerScreen):
517
524
  """Theme picker over console-window's themes plus vappman's 'mono'."""
518
525
 
526
+ def theme_label(self, theme_name):
527
+ """Name 'mono' while colour is off, so header and swatches agree.
528
+
529
+ With colour on the generic label names the installed palette. With
530
+ colour off the swatches are drawn from the monochrome role attributes,
531
+ so naming the palette left underneath would tell a different story.
532
+ """
533
+ if not colors_enabled():
534
+ return MONO_THEME
535
+ return super().theme_label(theme_name)
536
+
519
537
  def spin_theme_ACTION(self):
520
538
  """'t' advances to the next appearance (mono included) and persists it."""
521
539
  self.app.cycle_appearance()
@@ -596,8 +614,8 @@ class Vappman(Prerequisites):
596
614
 
597
615
  self.win = ConsoleWindow(win_opts)
598
616
  if not self.appearance_colors:
599
- # 'mono' is not a library theme; record it on the window for the
600
- # picker's header while the installed palette stays at the default.
617
+ # 'mono' is not a library theme: the installed palette stays at the
618
+ # default, but the window names the appearance actually in effect.
601
619
  self.win.theme = MONO_THEME
602
620
 
603
621
  # Initialize screens and screen stack
@@ -1038,8 +1056,9 @@ class Vappman(Prerequisites):
1038
1056
  """Make *name* live ('mono' turns colour off) and remember it.
1039
1057
 
1040
1058
  The preference is written immediately so an early exit cannot lose it,
1041
- and the window is told so its own ``theme`` (which the generic picker
1042
- reads for the header) matches the colour table that was installed.
1059
+ and the window is told which palette was installed; ``mono`` keeps its
1060
+ own name there so a reader of ``win.theme`` sees the no-colour
1061
+ appearance rather than the default palette left underneath.
1043
1062
  """
1044
1063
  mono = name == MONO_THEME
1045
1064
  self.appearance_colors = not mono
@@ -1048,8 +1067,8 @@ class Vappman(Prerequisites):
1048
1067
  set_colors_enabled(not mono)
1049
1068
  self.win.set_theme('default' if mono else name)
1050
1069
  if mono:
1051
- # 'mono' is not a library theme: record it for the picker's header
1052
- # while the installed palette stays at the library default.
1070
+ # 'mono' is not a library theme: the installed palette stays at the
1071
+ # library default, but the window names the appearance in effect.
1053
1072
  self.win.theme = MONO_THEME
1054
1073
  self.disk_state.theme = self.appearance_theme
1055
1074
  self.disk_state.colors = self.appearance_colors
File without changes
File without changes
File without changes