N/A
This commit is contained in:
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,5 +1,16 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 3.2.0
|
||||||
|
|
||||||
|
- Floating menu is anchored near the current cursor item instead of a fixed screen position.
|
||||||
|
- Added configurable archive, file, folder, shell and file-information menu actions.
|
||||||
|
- Added Pack as ZIP and Pack as tar.gz.
|
||||||
|
- Added Extract archive here for common archive formats.
|
||||||
|
- Added Rename, New folder, New file, Open shell here, SHA-256 and File information.
|
||||||
|
- Added generic `archive` menu condition.
|
||||||
|
- All menu entries remain configurable in `.tui`.
|
||||||
|
|
||||||
|
|
||||||
## 3.1.0
|
## 3.1.0
|
||||||
|
|
||||||
- Added floating action menu rendered over the browser without clearing the underlying file list.
|
- Added floating action menu rendered over the browser without clearing the underlying file list.
|
||||||
|
|||||||
132
tui/example.tui
132
tui/example.tui
@@ -1,5 +1,4 @@
|
|||||||
# TUI configuration. The Python program only provides the generic UI engine;
|
# TUI configuration. UI behavior, labels, shortcuts and actions belong here.
|
||||||
# actions, labels, shortcuts and context-specific menu entries live here.
|
|
||||||
|
|
||||||
keys:
|
keys:
|
||||||
up: up
|
up: up
|
||||||
@@ -13,7 +12,6 @@ keys:
|
|||||||
folder: enter
|
folder: enter
|
||||||
file:
|
file:
|
||||||
- "*.zip": list-zip
|
- "*.zip": list-zip
|
||||||
- "*.md": view
|
|
||||||
|
|
||||||
enter:
|
enter:
|
||||||
folder: enter
|
folder: enter
|
||||||
@@ -39,14 +37,6 @@ keys:
|
|||||||
folder:
|
folder:
|
||||||
- "*": delete
|
- "*": delete
|
||||||
|
|
||||||
# M opens this menu. The menu is entirely data-driven.
|
|
||||||
#
|
|
||||||
# selection: auto -> marked objects if there are marks, otherwise current object
|
|
||||||
# selection: current -> always current object
|
|
||||||
# selection: marked -> only when there is a marked selection
|
|
||||||
# selection: none -> action runs in the current directory, without a target
|
|
||||||
#
|
|
||||||
# when: git means this directory is inside a Git worktree.
|
|
||||||
menu:
|
menu:
|
||||||
- label: "View"
|
- label: "View"
|
||||||
key: v
|
key: v
|
||||||
@@ -58,6 +48,13 @@ menu:
|
|||||||
action: edit
|
action: edit
|
||||||
when: file
|
when: file
|
||||||
|
|
||||||
|
- label: "List archive"
|
||||||
|
key: l
|
||||||
|
action: list-zip
|
||||||
|
when:
|
||||||
|
- file
|
||||||
|
- glob:*.zip
|
||||||
|
|
||||||
- separator: true
|
- separator: true
|
||||||
|
|
||||||
- label: "Copy"
|
- label: "Copy"
|
||||||
@@ -75,6 +72,56 @@ menu:
|
|||||||
action: delete
|
action: delete
|
||||||
selection: auto
|
selection: auto
|
||||||
|
|
||||||
|
- label: "Rename"
|
||||||
|
key: r
|
||||||
|
action: rename
|
||||||
|
selection: current
|
||||||
|
|
||||||
|
- separator: true
|
||||||
|
|
||||||
|
- label: "Pack as ZIP"
|
||||||
|
key: z
|
||||||
|
action: pack-zip
|
||||||
|
selection: auto
|
||||||
|
|
||||||
|
- label: "Pack as tar.gz"
|
||||||
|
key: t
|
||||||
|
action: pack-targz
|
||||||
|
selection: auto
|
||||||
|
|
||||||
|
- label: "Extract archive here"
|
||||||
|
key: x
|
||||||
|
action: extract
|
||||||
|
when: archive
|
||||||
|
selection: current
|
||||||
|
|
||||||
|
- separator: true
|
||||||
|
|
||||||
|
- label: "New folder"
|
||||||
|
key: n
|
||||||
|
action: new-folder
|
||||||
|
selection: none
|
||||||
|
|
||||||
|
- label: "New file"
|
||||||
|
key: f
|
||||||
|
action: new-file
|
||||||
|
selection: none
|
||||||
|
|
||||||
|
- label: "Open shell here"
|
||||||
|
key: s
|
||||||
|
action: shell
|
||||||
|
selection: none
|
||||||
|
|
||||||
|
- label: "SHA-256"
|
||||||
|
key: h
|
||||||
|
action: sha256
|
||||||
|
selection: auto
|
||||||
|
|
||||||
|
- label: "File information"
|
||||||
|
key: i
|
||||||
|
action: info
|
||||||
|
selection: auto
|
||||||
|
|
||||||
- separator: true
|
- separator: true
|
||||||
|
|
||||||
- label: "Git: Status"
|
- label: "Git: Status"
|
||||||
@@ -88,6 +135,11 @@ menu:
|
|||||||
selection: none
|
selection: none
|
||||||
when: git
|
when: git
|
||||||
|
|
||||||
|
- label: "Git: Add -A"
|
||||||
|
action: git-add
|
||||||
|
selection: none
|
||||||
|
when: git
|
||||||
|
|
||||||
- label: "Git: Diff"
|
- label: "Git: Diff"
|
||||||
action: git-diff
|
action: git-diff
|
||||||
selection: none
|
selection: none
|
||||||
@@ -98,11 +150,6 @@ menu:
|
|||||||
selection: none
|
selection: none
|
||||||
when: git
|
when: git
|
||||||
|
|
||||||
- label: "Git: Add -A"
|
|
||||||
action: git-add
|
|
||||||
selection: none
|
|
||||||
when: git
|
|
||||||
|
|
||||||
- label: "Git: Commit"
|
- label: "Git: Commit"
|
||||||
action: git-commit
|
action: git-commit
|
||||||
selection: none
|
selection: none
|
||||||
@@ -120,21 +167,54 @@ actions:
|
|||||||
- read -rp "Press Enter to continue..."
|
- read -rp "Press Enter to continue..."
|
||||||
|
|
||||||
copy:
|
copy:
|
||||||
command: cp -v <path> <dir>copy_<name>
|
command: cp -v -- <path> <dir>copy_<name>
|
||||||
|
|
||||||
move:
|
move:
|
||||||
command: mv -v <path> <dir>
|
command: mv -v -- <path> <dir>
|
||||||
|
|
||||||
delete:
|
delete:
|
||||||
command: rm -v <path>
|
command: rm -v -- <path>
|
||||||
|
|
||||||
edit:
|
rename:
|
||||||
command: joe <path>
|
command: 'read -rp "New name for <name>: " new_name && mv -v -- <path> "<dir>$new_name"'
|
||||||
|
|
||||||
view:
|
view:
|
||||||
command: less <path>
|
command: less <path>
|
||||||
|
|
||||||
# target: none means that the action runs once in the current TUI folder.
|
edit:
|
||||||
|
command: joe <path>
|
||||||
|
|
||||||
|
pack-zip:
|
||||||
|
command: 'zip -r "<dir><name>.zip" <path>'
|
||||||
|
|
||||||
|
pack-targz:
|
||||||
|
command: 'tar -czvf "<dir><name>.tar.gz" <name>'
|
||||||
|
|
||||||
|
extract:
|
||||||
|
command:
|
||||||
|
- 'case "<path>" in *.zip) unzip -o -- <path> -d <dir> ;; *.tar.gz|*.tgz) tar -xzvf <path> -C <dir> ;; *.tar.bz2|*.tbz2) tar -xjvf <path> -C <dir> ;; *.tar.xz|*.txz) tar -xJvf <path> -C <dir> ;; *.tar) tar -xvf <path> -C <dir> ;; *.7z) 7z x <path> -o<dir> ;; *.rar) unrar x <path> <dir> ;; *) echo "Unsupported archive: <path>"; false ;; esac'
|
||||||
|
- read -rp "Press Enter to continue..."
|
||||||
|
|
||||||
|
new-folder:
|
||||||
|
target: none
|
||||||
|
command: 'read -rp "Folder name: " name && mkdir -pv -- "$name"'
|
||||||
|
|
||||||
|
new-file:
|
||||||
|
target: none
|
||||||
|
command: 'read -rp "File name: " name && touch -- "$name"'
|
||||||
|
|
||||||
|
shell:
|
||||||
|
target: none
|
||||||
|
command: 'bash'
|
||||||
|
|
||||||
|
sha256:
|
||||||
|
command: sha256sum <path>
|
||||||
|
|
||||||
|
info:
|
||||||
|
command:
|
||||||
|
- 'stat -- <path>'
|
||||||
|
- read -rp "Press Enter to continue..."
|
||||||
|
|
||||||
git-status:
|
git-status:
|
||||||
target: none
|
target: none
|
||||||
command: git status
|
command: git status
|
||||||
@@ -143,6 +223,10 @@ actions:
|
|||||||
target: none
|
target: none
|
||||||
command: git pull
|
command: git pull
|
||||||
|
|
||||||
|
git-add:
|
||||||
|
target: none
|
||||||
|
command: git add -A
|
||||||
|
|
||||||
git-diff:
|
git-diff:
|
||||||
target: none
|
target: none
|
||||||
command: git diff
|
command: git diff
|
||||||
@@ -151,10 +235,6 @@ actions:
|
|||||||
target: none
|
target: none
|
||||||
command: git log --oneline --decorate -20
|
command: git log --oneline --decorate -20
|
||||||
|
|
||||||
git-add:
|
|
||||||
target: none
|
|
||||||
command: git add -A
|
|
||||||
|
|
||||||
git-commit:
|
git-commit:
|
||||||
target: none
|
target: none
|
||||||
command: git commit
|
command: git commit
|
||||||
|
|||||||
23
tui/tui.py
23
tui/tui.py
@@ -6,7 +6,7 @@ import os
|
|||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
TUI_VERSION = "3.1.0"
|
TUI_VERSION = "3.2.0"
|
||||||
SHELL_HANDOFF = 42
|
SHELL_HANDOFF = 42
|
||||||
TUI_EXIT = 43
|
TUI_EXIT = 43
|
||||||
|
|
||||||
@@ -146,6 +146,14 @@ class TuiConfig:
|
|||||||
if condition == "folder":
|
if condition == "folder":
|
||||||
target = browser.selected()
|
target = browser.selected()
|
||||||
return bool(target and target.is_dir())
|
return bool(target and target.is_dir())
|
||||||
|
if condition == "archive":
|
||||||
|
target = browser.selected()
|
||||||
|
if not target or not target.is_file():
|
||||||
|
return False
|
||||||
|
return target.suffix.lower() in {
|
||||||
|
".zip", ".tar", ".gz", ".tgz", ".bz2", ".tbz2",
|
||||||
|
".xz", ".txz", ".7z", ".rar",
|
||||||
|
} or target.name.lower().endswith((".tar.gz", ".tar.bz2", ".tar.xz"))
|
||||||
if condition == "marked":
|
if condition == "marked":
|
||||||
return bool(browser.marked)
|
return bool(browser.marked)
|
||||||
if condition == "multiple":
|
if condition == "multiple":
|
||||||
@@ -579,7 +587,18 @@ def show_menu(stdscr, browser):
|
|||||||
menu_top = max(1, cursor_screen_row - menu_rows - 1)
|
menu_top = max(1, cursor_screen_row - menu_rows - 1)
|
||||||
if menu_top + menu_rows > height - 1:
|
if menu_top + menu_rows > height - 1:
|
||||||
menu_top = max(1, height - 1 - menu_rows)
|
menu_top = max(1, height - 1 - menu_rows)
|
||||||
menu_left = max(1, min((width - menu_width) // 2, width - menu_width - 1))
|
# Anchor the floating menu near the current item rather than at a
|
||||||
|
# fixed screen position. The current row remains visible because the
|
||||||
|
# menu starts after the item's text when there is enough room.
|
||||||
|
if browser.cursor == 0:
|
||||||
|
cursor_text = "../" if browser.path != browser.root else "./"
|
||||||
|
elif 1 <= browser.cursor <= len(browser.entries):
|
||||||
|
current = browser.entries[browser.cursor - 1]
|
||||||
|
cursor_text = current.name + ("/" if current.is_dir() else "")
|
||||||
|
else:
|
||||||
|
cursor_text = ""
|
||||||
|
preferred_left = min(max(2, len(cursor_text) + 3), max(2, width - menu_width - 2))
|
||||||
|
menu_left = max(1, min(preferred_left, width - menu_width - 1))
|
||||||
|
|
||||||
win = curses.newwin(menu_rows, menu_width, menu_top, menu_left)
|
win = curses.newwin(menu_rows, menu_width, menu_top, menu_left)
|
||||||
win.keypad(True)
|
win.keypad(True)
|
||||||
|
|||||||
Reference in New Issue
Block a user