# Python 3.10+ required (PuiKit, XeFM's UI framework, requires 3.10+)
# pygments for syntax highlighting (will fallback gracefully if not available)
# boto3 for AWS S3 support
# watchdog for automatic file list reloading
# pillow for the built-in image viewer (decode/crop/scale; the viewer degrades
#   to a metadata card without it, and inline terminal images need it too).
#   Pillow's own format registry is half of what the viewer claims to open --
#   11.3+ bundles libavif, so AVIF needs nothing else -- and any Pillow plugin
#   installed alongside it (pillow-heif, pillow-jxl-plugin) is picked up with no
#   entry here and no XeFM-side switch. None of those plugins is required:
#   their wheels bundle LGPL codecs the DMG and MSIX would have to attribute, to
#   serve formats macOS and Windows already read natively. See
#   xefm/image_decoders.py.
# libarchive-c for archive formats the standard library cannot read (.7z, .rar,
#   .iso, .cab, .cpio, .rpm); see the note above the pin for why it is optional
# pymigemo for Migemo (romaji -> Japanese) matching in incremental search
#   (will fallback gracefully to plain matching if not available)
#
# Backend/platform deps (pyobjc on macOS, windows-curses on Windows, numpy on
# Windows) are PuiKit's own requirements and resolve transitively via the puikit
# pin below, so XeFM does not list them here. pillow is listed because XeFM's
# image viewer imports PIL directly, independent of PuiKit.

# PuiKit is XeFM's UI/rendering framework (the TUI/GUI backend layer), published
# on PyPI as of 1.0. For co-development against a local checkout, ``make venv``
# additionally installs it editable from ../puikit, which overrides this pin.
# 1.9.0 is the floor, and a hard one: the first launch asks which keymap
# preset to use with a message box that Esc must not close (#597), opened with
# ``show_message_box(..., dismissable=False)`` -- a TypeError on any older
# PuiKit, so a first launch would fail before the window was usable. It also
# carries what this XeFM uses where it can: the file clipboard bridge to Finder
# and Explorer (``clipboard_files``, #577, puikit#155), modifiers on desktop
# mouse events, side buttons and the drop operation (#589, puikit#156), the
# drop target answering the cursor badge (``FILE_DRAG_OVER``) and a click on
# the pane footer reaching it through the splitter's grab band (puikit#157),
# and a popup menu opening above a modal dialog in a terminal (puikit#159).
# Those older PuiKits only lack; the message box is what breaks.
# 1.8.0 was the previous floor, and a hard one: the conflict dialog and the compare
# dialog size their boxes before they open through ``Panel.layout_context()``,
# an AttributeError on any older PuiKit, so neither would open -- a copy or
# move that hits an existing file would stall on a prompt that never appears.
# The conflict dialog also asks its message for its height with
# ``MarkdownView.measure`` (on an older PuiKit the base ``measure`` answers 0,
# and the size/date table would be clipped) and reads ``LayoutContext
# .vector_shapes``. All three arrived in puikit 1.8.0 (issue #545, puikit#154),
# with ``LayoutContext`` measuring a style in the face it is drawn in.
# 1.7.7 was the previous floor, and a hard one: every Markdown dialog -- Help, file
# details, a viewer's key list, an action's page -- builds its MarkdownView with
# ``on_link=``, a TypeError on any older PuiKit, so none of them would open.
# 1.7.7 is where that per-view link handler arrived, with keyboard link focus
# (``focus_advance`` / ``activate_focused_link``): Tab / Enter in the Help dialog
# reach a row's link and open that action's page over the help (discussion
# #550, puikit#153).
# 1.7.6 was the previous floor, and a soft one: XeFM calls nothing new for it, and nothing
# raises without it. It is what makes the context menus say which row they are
# for, and what delivers the Menu key. A native popup menu (macOS, Windows)
# holds the UI thread until it closes while a render only schedules a redraw,
# so a right-click moved the cursor onto the clicked row and the screen kept
# the old frame for as long as the menu was open; 1.7.6 draws the pending frame
# before the menu opens (puikit#151). It also names the PC keyboard's Menu key
# 'apps' (puikit#152), which the APPS / Shift-APPS context-menu bindings need.
# On an older PuiKit the menus still open and '/' and '?' still work; the
# cursor catches up when the menu closes, and the Menu key does nothing.
# 1.7.5 was the previous floor, and a soft one: XeFM calls nothing new for it, and nothing
# raises without it. It is what lets a full-width space be typed (issue #508).
# With a Japanese IME on, the space bar types U+3000, and every PuiKit backend
# decided "is this text?" with str.isprintable(), which rejects every Unicode
# space separator but the ASCII one -- so the rename dialog, and every other
# text field, silently dropped it. 1.7.5 admits the space separators as text.
# On an older PuiKit the fields still work; they only refuse that character.
# 1.7.4 was the previous floor, and a soft one: XeFM calls nothing new for it, and nothing
# raises without it. It is what keeps a long name readable while it is edited
# (issue #480). PuiKit's TextEdit scrolled only once the caret itself left the
# field and never scrolled back, so Backspacing from the end of a long name in
# the rename dialog left the start of the name hidden off the left while a blank
# run grew on the right -- the user deleted blind until they pressed Home.
# 1.7.4 keeps a few columns of text visible past the caret on either side and
# pulls hidden text back in whenever an edit shortens the line. Every XeFM text
# field gets it -- rename, the input and connect dialogs, batch rename, the
# filter list and the search bar. On an older PuiKit the fields still work;
# they only scroll the old way.
# 1.7.3 was the previous floor, and on the Windows TUI an absolute one: 1.7.2 -- the floor
# it replaces, for the reason recorded just below -- reads the NUL byte as
# Ctrl+Space on every TUI input path, while the Windows console sends NUL for
# every key that produced no character. So there the arrows, F1-F12,
# Home/End/PageUp/PageDown and Insert/Delete all arrive as that chord, and
# holding Shift alone marks a file: the Windows terminal app cannot be driven at
# all on 1.7.2. Nothing raises, and no other platform or backend is touched --
# which is why the pin has to carry it, the version that is new enough for the
# feature being the one that breaks the app. 1.7.3 drops the NUL where the
# Windows console builds its key record, before anything reads it as a character.
# 1.7.2 was the previous floor, and a soft one in shape but not in effect: XeFM
# calls nothing new for it, and nothing raises without it -- a TUI simply loses
# a key.
# Ctrl+Space is the search bar's marking key (issue #266 moved it there, where
# Space itself types into the pattern), and in a terminal that chord arrives as
# the NUL byte. PuiKit decoded only 0x01..0x1A, the Ctrl+letter run one byte
# above, so NUL fell past every branch and was dropped: on an older PuiKit
# 'isearch.toggle_select_down' cannot fire in the TUI at all, while both GUI
# backends and the Windows console -- which report the modifier natively -- are
# unaffected. 1.7.2 names the byte in both TUI input paths (VT and curses).
# 1.7.1 was the previous floor, and a soft one: XeFM called nothing new for it
# either. It is what makes the image viewer's own overlays land in FRONT of the
# picture on the TUI.
# A terminal has no compositor, so a picture is written out of band and has to
# go out after the cell grid -- which put it in front of everything, whatever
# layer each came from, so pressing ``?`` over an image drew the help dialog
# behind it and then re-sent the picture over what little showed (issue #458).
# PuiKit 1.7.1 makes the VT backend follow draw order instead, the rule the GUI
# backends already followed, so the layer z XeFM already sets is honoured there
# too. On an older PuiKit the viewer still works and the help is still reachable
# -- it is simply unreadable while a picture is under it.
# 1.7.0 was the previous floor, and a hard one: the image viewer asks the backend which
# formats it draws from a path (``Panel.image_formats()``) and hands it decoded
# pixels for the ones it does not (``puikit.image.RasterImage``) -- an
# AttributeError at startup and an ImportError at import on any older PuiKit.
# That pairing is what widened the supported image formats: HEIC, JPEG XL and
# camera RAW are drawn by the OS's own decoder where there is one, and a format
# only XeFM can decode (a config's IMAGE_DECODERS entry, a Pillow plugin) is
# handed over as pixels rather than written back out as a PNG. 1.7.0 also makes
# every backend answer ``image_size`` through that same native decoder, which is
# what makes the size -- and so the picture -- available for those formats at
# all; and it lets a *terminal* borrow the OS decoder too, which is the whole
# reason the terminal app shows a HEIC the desktop app on the same machine was
# already showing. None of that last part is a floor of its own: on an older
# PuiKit the formats simply are not claimed. See discussion #378 and
# doc/dev/IMAGE_VIEWER_IMPLEMENTATION.md.
# 1.6.0 was the previous floor, and a hard one: on the macOS GUI the main window is
# opened with ``WindowStyle(takes_first_click=True)`` so that a drag out of a
# background XeFM starts on the first press rather than being spent bringing
# the window forward (issue #431) -- an unexpected keyword, so a TypeError at
# startup, on any older PuiKit. 1.6.0 also carries ``MenuBar.set_menu``, which
# a config reload hands the rebuilt menu so it stops naming the key the user
# just bound away from (issue #382), an AttributeError before it existed; and
# the gate that quiets an OS menu bar under a modal layer, which XeFM never
# calls but relies on -- without it a menu item stays live under an open dialog
# and drives the file list behind it (issue #388).
# 1.5.4 was the previous floor, and a hard one: before printing the menu-bar
# row the help dialog asks ``MenuBar.takes_activation_key`` whether that key
# opens anything, an AttributeError on any older PuiKit -- so opening help
# raises instead of drawing. 1.5.4 also carries the Markdown fix the same
# dialog depends on: a table cell holding a lone backslash (what ``go_root``
# is bound to) came back an empty code span, the backslash and its closing
# backtick both eaten as an escape (issue #389).
# 1.5.3 was the floor before that, and a soft one: it carries the UI-thread stall
# detector ``--ui-watchdog`` turns on (issue #407), a developer diagnostic, so an
# older PuiKit costs the switch and nothing else -- XeFM says so at startup
# rather than staying silent. It also carries the fix that makes the switch work
# on the TUI at all: VTBackend never recorded its UI thread, so the detector had
# no subject there (and ``_assert_ui_thread`` nothing to check against).
# 1.5.0 is the hard floor under that one: the TUI cursor cue passes
# ``Style(underline_color=...)``, a TypeError on any older PuiKit, and reads the
# ``colored_underlines`` capability, an AttributeError -- so a file pane cannot
# draw a row at all. Both arrived in puikit 1.5.0 (issue #350).
# The floors underneath it are recorded because they are still the answer to
# "why not lower": 1.4.3 drew the CSV / TSV table viewer's header wrong, a
# full-width (CJK) cell making PuiKit's TableView lay a row out wider than its
# own column rules (issue #355); and 1.2.0 is where the calls XeFM makes
# arrived -- the rich viewers' ``search_matcher`` hook (Migemo in incremental
# search -- issue #302), ``Panel.remove_layer`` (the progress dialog closing
# itself from under a covering confirm box -- issue #333), and
# ``MenuBar.open_menu`` / ``open_menu_mnemonic`` (keyboard menu activation --
# issue #304).
puikit>=1.9.0
pygments
boto3
watchdog
pillow

# The ctypes binding for libarchive, which is how XeFM reads .7z, .rar, .iso,
# .cab, .cpio and .rpm. It is pure Python and carries no binary of its own, so
# the shared library still has to come from somewhere: a bundled copy, the
# LIBARCHIVE environment variable, or the system — macOS and most Linux
# distributions already have one new enough. When none of those answers, XeFM
# logs why at startup and offers zip and tar only; nothing else degrades, which
# is why this is an ordinary requirement rather than a hard dependency with a
# platform marker. See doc/dev/ARCHIVE_SYSTEM.md.
libarchive-c

# Pinned exactly: 0.0.1's dictionary reader breaks on LP64 platforms
# (macOS/Linux) and xefm/migemo_search.py patches it at runtime — a future
# upstream release could move the internals that patch touches. See
# discussion #332 before bumping.
pymigemo==0.0.1
# doc-files reads what PDF, Office, OpenDocument and EPUB files say, for the
# viewer's documents-as-text and content search (#575). Pure Python with no
# dependencies of its own; the [pdf] extra adds pypdf, pure Python too.
# Without it those files show the "binary file" placeholder, so it is an
# ordinary requirement: every install, the desktop apps included, reads them.
doc-files[pdf]>=0.1.0
# similar-files finds identical and similar files for Find Similar Files
# (#571). XeFM runs it as a program of its own (python -m similar_files) and
# reads the .xft tree it writes; 0.2.0 is the floor because that is where
# --status, --stop-file and --format tree arrived, and where the tree became
# .xft (#613). Pure Python; the [image] extra adds only Pillow, which XeFM
# already requires. Video and audio need ffmpeg / fpcalc on PATH, which the
# menu names when they are missing.
similar-files[image]>=0.2.0
# comtypes reaches Windows Search (the OS's own file index) over COM, for
# index_search (#579): OLE DB against Search.CollatorDSO. Pure Python on
# ctypes, Windows only. macOS needs nothing -- Spotlight is queried through
# /usr/bin/mdfind. Without it the action says how to install it.
comtypes; sys_platform == "win32"
