meta_package_manager.bar_plugin_renderer module¶
Renderer on the mpm side, which builds the SwiftBar and Xbar plugin
output.
This code is in its own module. meta_package_manager.bar_plugin uses
the Python standard library only, because its
MPMPlugin class is the script that
the user installs as the bar plugin, and that script must have few
dependencies.
This module is the companion on the mpm side. It adds click_extra, boltons,
the manager pool and the theme system to the plugin code, and produces the
final output of mpm outdated --plugin-output.
- meta_package_manager.bar_plugin_renderer.MAX_VERSION_WIDTH = 18¶
Maximum width of a version in a menu line, in characters.
A macOS menu cannot scroll sideways and a menu item is one line high, so a row wider than the menu loses its end. SwiftBar keeps the AppKit default paragraph style
.byWordWrapping, which moves the last token to a second line that the item does not draw. That token is the new version, so one package with a long version hides the column that the menu shows. The limit also helps the other rows, because the table aligns on the widest cell of the column.The value
18comes from a survey of 1087 version strings: 578 from the bundled[samples]fixtures and the manager docstrings, and 509 from the inventory of one macOS system. The two groups are far apart. A version that a person reads is 17 characters long at most (152.0.7977.82-1.1, a Homebrew cask). A machine identifier starts at 26 characters: a Julia build triple, a commit SHA of 40 characters, and Homebrew’s 50-characterversion,revisionpair.18is the smallest limit that keeps all of the first group. In the fixtures, the Linux package managers reach 22 characters (2.7+git1722+daf2f52-r0, an OpenWrt package). This renderer never sees them, because SwiftBar and Xbar run on macOS only.Set the
VAR_MAX_VERSION_WIDTHenvironment variable to change this value. SeeBarPluginRenderer.max_version_width().
- meta_package_manager.bar_plugin_renderer.VERSION_ELLIPSIS = '…'¶
Marker for the characters that
MAX_VERSION_WIDTHremoves.It is one character wide in a monospace font, so the table loses one column.
...would lose three.
- meta_package_manager.bar_plugin_renderer.VERSION_PREFIX_COLOR = 245¶
Index in the xterm-256 palette for the unchanged prefix of a version.
The CLI table keeps the default
bright_black(SGR90) ofmeta_package_manager.version.diff_versions(), and a terminal changes that color to match its own theme. SwiftBar always maps SGR90to the fixedNSColor.darkGray, which is hard to see on a dark menu. Its support of 256 colors renders the palette index245as a mid-gray (#8a8a8a) that does not depend on the theme and is readable in both appearances. Xbar removes the ANSI codes that it does not render, so this choice has no effect there.
- meta_package_manager.bar_plugin_renderer.LIGHT_MENU_OLD_COLOR = 124¶
Palette index for the red suffix of the old version on a light menu.
#af0000, with a contrast ratio of6.5:1on the cream material. SeeBarPluginRenderer.menu_diff_colors()for the reason for this value.
- meta_package_manager.bar_plugin_renderer.LIGHT_MENU_NEW_COLOR = 23¶
Palette index for the green suffix of the new version on a light menu.
#006600, with a contrast ratio of6.3:1on the cream material. SeeBarPluginRenderer.menu_diff_colors().
- meta_package_manager.bar_plugin_renderer.DARK_MENU_NEW_COLOR = 46¶
Palette index for the green suffix of the new version on a dark menu.
#00ff00. It raises the worst contrast from4.0:1, the value of the adaptiveNSColor.systemGreen, to5.8:1when a bright wallpaper shows through the translucent menu. The red suffix of the old version keepssystemRed. It is already the most readable red in the xterm-256 palette: a pure#ff0000has a lower ratio, and a brighter red looks orange. SeeBarPluginRenderer.menu_diff_colors().
- meta_package_manager.bar_plugin_renderer.elide_versions(old, new, width)[source]¶
Shorten a pair of versions to
widthcharacters, and keep the two versions different.The function removes the end of each version first. The end holds the part that nobody reads: a commit SHA, a platform triple, or Homebrew’s
version,revisionpair. That method does not work for a rebuild whose last characters are the only difference (2.6.0-2.suse1699.10against its.11), because the two results would be the same string with an arrow between them. The function then removes the common start instead. It puts the…at the boundary thatcommon_prefix_length()reports, so the marker sits between the gray prefix and the colored suffix.The function makes this choice for the pair, and not for each version on its own. With a choice per version, one run rendered
5.0.0~beta1-0ubuntu7as….0~beta1-0ubuntu7next to5.0.2-0ubuntu1~26…, which had kept its start. The column did not line up, and one side alone lost its5.0.
- class meta_package_manager.bar_plugin_renderer.BarPluginRenderer[source]¶
Bases:
MPMPluginRenders
mpm outdatedin the SwiftBar and Xbar plugin dialect.This class adds the rendering to
MPMPlugin. The rendering can use mpm’s own dependencies. See the module docstring for the division between the two modules.- property group_by_manager: bool[source]¶
Give each manager its own section, in place of one flat list.
Each host draws that section in its own way: Xbar opens a sub-menu, SwiftBar folds an accordion into the same menu, and the GNOME Shell extension expands the section inline. The name of this option describes the grouping itself, and not the way one host draws it.
The value comes from the
VAR_GROUP_BY_MANAGERenvironment variable.
- property fold_sections: bool[source]¶
Render the manager sections as inline accordions instead of sub-menus.
SwiftBar
2.1.0renders an item withfold=trueand its---prefixed children as one collapsible section. A click on the header expands the section in place. It does not open a sub-menu and it does not close the menu. The expanded state stays after a refresh (swiftbar/SwiftBar#480).This option needs
group_by_manager, which provides the children to fold. Xbar has no equivalent parameter and ignores it, so its grouped layout keeps the sub-menus.
- property own_panel_per_manager: bool[source]¶
Truewhen the packages of each manager have a panel of their own.This is true for Xbar’s grouped layout only, where a
---prefixed row opens a sub-menu. SwiftBar folds the same rows into the same menu, and the flat layout stays in one menu too. In those cases every package is in one continuous column.
- property max_version_width: int[source]¶
Maximum width of a rendered version, in characters, before the renderer shortens it.
The value comes from the
VAR_MAX_VERSION_WIDTHenvironment variable, and its default isMAX_VERSION_WIDTH. A value lower than2leaves no space for the ellipsis and for one character of content, so the code reads it as no limit.
Colors of the version-diff suffixes, adapted to the menu appearance.
SwiftBar maps the default SGR
31and32suffixes ofmeta_package_manager.version.diff_versions()to the adaptive colorsNSColor.systemRedandNSColor.systemGreen. It also puts the menu appearance in theOS_APPEARANCEenvironment variable, which thempm outdated --plugin-outputsubprocess inherits. On the translucent “Liquid Glass” menus of recent macOS releases, these system colors have too little contrast with the material. The method replaces them for each appearance:On a light menu, both suffixes are too pale. The measured contrast of the green is
1.9:1. The method uses the darkerLIGHT_MENU_OLD_COLORandLIGHT_MENU_NEW_COLOR.On a dark menu above a bright wallpaper, the contrast of the green falls to
4.0:1. The method uses the brighterDARK_MENU_NEW_COLOR, and keepssystemRedfor the red. That red is already the most readable red in the palette.
The result is a set of keyword arguments for
diff_versions. The method returns an empty mapping when the variable is not set, for a host like Xbar that removes these codes. The system colors then stay in force.
- property mpm_cli: tuple[str, ...][source]¶
Absolute
mpmcommand that runs the actions of the menu.The command starts the same interpreter that renders the menu. A click then runs the same
mpmthat the plugin called, and reads the same configuration file. The value comes fromsys.executable, not fromsys.argv[0].sys.executableis always an absolute path to a runnable entry point.sys.argv[0]can be a console script, a__main__.pyfile or a bare-c, and it depends on the waympmstarted. Anmpmcompiled with Nuitka is its own interpreter, so the code calls it directly, with no module.-Pkeeps the folder that the action starts from out ofsys.path. Without it,-mputs that folder first. An action started from a source checkout would then import that source tree, with the dependencies of the installed version. A7.6.1interpreter that read an8.0.0.dev0tree stopped onfrom click_extra.table import AUTO_WIDTH. The flag needs Python3.11. The interpreter that renders the menu is the one that the action starts, so its own version decides.Note
This code does not reuse the candidates that
meta_package_manager.bar_plugin.MPMPlugin.search_mpm()produces. The candidates from a virtual environment start with a bareuv,pipenvorpoetrycommand name. A bar app starts a menu action with thelaunchdPATHalone, and thatPATHcannot find such a name.
- property shell_env_options: tuple[str, ...]¶
--shell-envwhen the run rendering the menu adopted the login shell environment, nothing otherwise.An action starts the way the plugin does, outside a terminal, so it needs the environment the menu was rendered from. The flag is read off the root context of the
mpm outdated --plugin-outputrun, and stays ahead ofmpm_optionsso a--no-shell-envtyped there wins. A renderer built outside a run, like the test suite does, carries none.
- static render_cli(cmd_args)[source]¶
Return a command in the SwiftBar and Xbar plugin format.
The result is a string with this schema:
shell=cmd_args[0] param1=cmd_args[1] param2=cmd_args[2] ...
- Return type:
- print_cli_item(*args)[source]¶
Print two menu entries for one command:
one that opens a visible terminal, so the user can follow the execution
one that runs with no terminal, which the user reaches with the
Optionkey
- Return type:
- print_upgrade_all_item(manager, submenu='')[source]¶
Print the menu entry that upgrades every outdated package of one manager.
- Return type:
- package_rows(manager)[source]¶
Return one row of cells for each outdated package.
Each result holds the cells, the command that the row runs, and the tooltip with the full versions that the width limit removed.
- version_tooltip(old, new, elided)[source]¶
Return the full version pair for a menu item whose cells were shortened.
SwiftBar shows a
tooltipwhen the pointer is above the item, so the user can still read the characters thatmax_version_width()removed. The SwiftBar parser reads a quoted value as one piece, so the spaces around the arrow are safe. Xbar has no such parameter and would render the text as part of the label, so the method returns an empty string for Xbar.- Return type:
- static align_rows(rows)[source]¶
Put a set of rows into aligned columns.
The arrow is centered, so the user follows one vertical line down the column, and the versions grow away from it on both sides.
- align_managers(rows_by_manager)[source]¶
Align the rows of every manager, in one table or in one table per manager.
One table serves the layouts where the managers share a column: the flat layout and the SwiftBar accordion. A table sized for one manager aligns its own arrows, but those arrows then do not line up with the section above. In a menu that the user reads in one pass, that looks like a mistake.
One table per manager serves the layouts where each manager has a panel of its own. There, a width taken from all the managers would pad every short sub-menu to the longest package name in the report.
- render(outdated_data)[source]¶
Call
_render()and capture its<stdout>output.Every method on the
_renderpath writes with a plainprintcall, and that includes the inheritedppandprint_error. One redirection of<stdout>then captures the whole rendering.- Return type:
- add_upgrade_cli(outdated_data)[source]¶
Add the upgrade commands to the data of
mpm outdated, for the bar plugin.Every menu action is one
mpm_clicall limited to the manager of the section (mpm --brew upgrade wget). It is never the native command of that manager. A click that goes throughmpmfollows the same settings as the run that rendered the menu: the configuration file on the system, and with it the release-age cooldown, the manager selection, the sudo policy and the per-manager overrides. A native command ignores all of them, and would upgrade a package thatmpmwould have stopped.The command passes only the manager selector, the operation and the package.
mpmreads every other setting from the user’s configuration at the time of the click. The package is a pURL (manager_purl()), which names the section’s manager.mpmthen upgrades the package without a search in the installed packages. That search misses the packages that a manager reports as outdated but not as installed.A manager gets the action only when it
implements()it. This is the same test thatmpmuses to route the subcommand. A manager thatmpmwould skip gets aNonecommand, and the menu renders its label alone.
- print(outdated_data)[source]¶
Print the final plugin rendering to
<stdout>.Capturing the output and printing it again would add one line break, so the call to
rstrip()removes it.The colors are forced on, and
echodoes not run its own detection. The bar plugin capturesmpm outdated --plugin-outputthrough a pipe, andechowould remove every ANSI code there. The colors of the version diff would then never reach SwiftBar or Xbar. A TTY test has no meaning for this dialect, which sets the rendering of ANSI codes line by line with theansi=trueandansi=falseparameters. An explicit opt-out (--color=never,NO_COLOR) still applies: the code replaces the automatic (None) state only. The value comes frominvocation_color(), not fromctx.color, so it is also correct for a rendering on a worker thread. The command context is thread-local and does not reach such a thread.- Return type: