定制 sugarcraft/candy-files 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

sugarcraft/candy-files

Composer 安装命令:

composer create-project sugarcraft/candy-files

包简介

Dual-pane terminal file manager built on the SugarCraft stack. Inspired by superfile and Midnight Commander. Navigate two directories side-by-side, sort by name / mtime / size, multi-select, delete with confirmation, swap focus with Tab.

README 文档

README

candy-files

CandyFiles

CI codecov Packagist Version License PHP

demo

Dual-pane terminal file manager built on the SugarCraft stack — port of yorukot/superfile, with the Midnight Commander look.

┌────────────────────────────────────┐  ┌────────────────────────────────────┐
│ /home/alice  [name-asc]            │  │ /var/log  [mtime-desc]             │
│ ──────────────────                 │  │ ──────────────────                 │
│ ▸  ../                       DIR   │  │    ../                       DIR   │
│    Documents/               DIR   │  │ ▸✓ syslog                  240KB  │
│    Downloads/               DIR   │  │    auth.log                 12KB  │
│    .config/                 DIR   │  │    Xorg.0.log              4.0KB  │
│    notes.md                12KB   │  │                                    │
│    todo.txt              512B    │  │                                    │
└────────────────────────────────────┘  └────────────────────────────────────┘
 Tab swap · ↑↓ jk move · Enter open · ← h up · space select · s sort · . hidden · d delete · r refresh · q quit · / search · t tabs · u undo

Run it

composer install
./bin/candyfiles [LEFT_DIR] [RIGHT_DIR]

Default: left pane = current directory, right pane = $HOME.

Keys

Key Action
Tab Swap focus between panes
/ k Move cursor up
/ j Move cursor down
Home / g Top of listing
End / G Bottom of listing
Enter / Open directory (or no-op on a file)
/ h Go up one directory
Space Toggle selection on the entry under cursor + advance
s Cycle sort order (name → mtime → size, asc / desc)
. Toggle hidden-file visibility
c Copy (selection or cursor) to inactive pane; y confirm
m Move (selection or cursor) to inactive pane; y confirm
R Rename (cursor entry); new name prompted; y confirm
d Delete (selection or cursor); requires y confirm
r Refresh active pane
q Quit
/ Start search mode; type to filter; Enter to open
Escape Exit search mode
t Duplicate current tab
Ctrl+w Close current tab
Ctrl+Tab Cycle to next tab
Ctrl+Shift+Tab Cycle to previous tab
u / Ctrl+z Undo last operation

Architecture

The whole transition layer is pure — filesystem I/O is injected as a Closure(string $path): list<Entry> so every transition is unit-testable without tmp dirs or stat fixtures.

File Role
Entry Value object: name, isDir, size, mtime, isLink, isHidden
Sort Enum (NameAsc/NameDesc/MtimeAsc/MtimeDesc/SizeAsc/SizeDesc) + comparator
Pane One pane: cwd, entries, cursor, selection set, sort, showHidden
ConfirmState Pending-confirmation enum (None / DeleteSelected)
Manager SugarCraft Model — orchestrates two panes, handles all keys + confirm gate
FsLister Default lister: scandir + lstat against the live filesystem
Renderer Pure view function — two pane boxes side-by-side + status line
BulkRename Bulk rename engine: regex template + sequential {n}/{name}/{ext} placeholders
PreviewPane File preview: ANSI image render via Mosaic for images, metadata block otherwise
AsyncOps Async copy/move/rename via React\Promise — keeps TUI responsive during I/O

Test plan

  • 36 tests / 65 assertions
  • Pure-state coverage: Entry (size formatting, parent sentinel), Sort (every order × dirs-first × cycle), Pane (open / navigate / move / select / sort / hidden toggle / parent-path / join)
  • Manager integration: Tab swap, key dispatch per pane, confirm gate (d arms, y confirms, anything else cancels), refresh status

Demos

Navigation

navigate

Search

search

Multi-select and delete

multi-select

Tab management

tabs

Sort cycling

sort-cycle

Undo delete

undo

Hidden-file toggle

hidden-files

Constructing Manager

Manager has 15 constructor parameters. Use the fluent builder for readability and to avoid parameter-order mistakes:

$manager = Manager::builder()
    ->withLeft($leftPane)
    ->withRight($rightPane)
    ->withActiveIdx(0)
    ->withStatus('')
    ->withConfirm(ConfirmState::None)
    ->withLister(fn(string $path): list<Entry> => FsLister::lister()($path))
    ->withSearchQuery(null)
    ->withSearchResults([])
    ->withSearchCursor(0)
    ->withTabs([])
    ->withTabIndex(0)
    ->withShowTabBar(false)
    ->withUndoStack([])
    ->withRedoStack([])
    ->withPendingOpDest(null)
    ->withPendingOpType(null)
    ->build();

The direct constructor is kept for backward compatibility only — new code should use Manager::builder().

Status

Phase 10 entry — copy / move / rename / undo are wired. Three-phase confirm gate (c/m/R arms, y confirms, anything else cancels). Undo restores delete/move/rename; copy undo is informational (original preserved). Everything underneath (the pure-state transition layer) is already in place.

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 2
  • 点击次数: 5
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 2
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-28