77
88from click ._termui_impl import ProgressBar
99from click_extra import echo , progressbar
10- from rich import print as rprint
10+ from rich .console import Console , RenderableType
11+ from rich .text import Text
1112from rich .tree import Tree
13+ from rich .table import Table
1214from rich .filesize import decimal
1315from geocompy .communication import open_serial
1416from geocompy .geo import GeoCom
1517from geocompy .geo .gctypes import GeoComCode
1618from geocompy .geo .gcdata import File , Device
1719
18- from ..utils import echo_red , echo_green , echo_yellow
20+ from ..utils import echo_red , echo_green
1921
2022
2123_FILE = {
4244
4345class FileTreeItem (TypedDict ):
4446 name : str
45- size : int | str
47+ size : int
48+ date : str
4649 children : list [FileTreeItem ]
4750
4851
49- def run_listing (
50- tps : GeoCom ,
51- dev : str ,
52- directory : str ,
53- filetype : str
54- ) -> None :
55- resp_setup = tps .ftr .setup_listing (
56- _DEVICE [dev ],
57- _FILE [filetype ],
58- directory
59- )
60- if resp_setup .error != GeoComCode .OK :
61- echo_red (f"Could not set up file listing ({ resp_setup .error .name } )" )
62- return
63-
64- resp_list = tps .ftr .list ()
65- if resp_list .error != GeoComCode .OK or resp_list .params is None :
66- echo_red (f"Could not start listing ({ resp_list .error .name } )" )
67- return
68-
69- last , name , size , lastmodified = resp_list .params
70- if name == "" :
71- echo_yellow ("Directory is empty or path does not exist" )
72- return
73-
74- count = 1
75- echo (f"{ 'file name' :<55.55s} { 'bytes' :>10.10s} { 'last modified' :>25.25s} " )
76- echo (f"{ '---------' :<55.55s} { '-----' :>10.10s} { '-------------' :>25.25s} " )
77- fmt = "{name:<55.55s}{size:>10s}{date:>25.25s}"
78- echo (
79- fmt .format_map (
80- {
81- "name" : name ,
82- "size" : str (size ),
83- "date" : (
84- lastmodified .isoformat (sep = " " )
85- if lastmodified is not None
86- else ""
87- )
88- }
89- )
90- )
91- while not last :
92- resp_list = tps .ftr .list (True )
93- if resp_list .error != GeoComCode .OK or resp_list .params is None :
94- echo_red (
95- f"An error occured during listing ({ resp_list .error .name } )"
96- )
97- return
98-
99- last , name , size , lastmodified = resp_list .params
100- echo (
101- fmt .format_map (
102- {
103- "name" : name ,
104- "size" : str (size ),
105- "date" : (
106- lastmodified .isoformat (sep = " " )
107- if lastmodified is not None
108- else ""
109- )
110- }
111- )
112- )
113- count += 1
114-
115- echo ("-" * 90 )
116- echo (f"total: { count } files" )
117-
118-
11952def get_directory_items (
12053 bar : ProgressBar [str ],
12154 tps : GeoCom ,
12255 device : str ,
12356 directory : str ,
57+ filetype : str ,
12458 depth : int = 0
12559) -> list [FileTreeItem ]:
12660 if depth == 0 :
12761 return []
12862 bar .update (1 , directory )
12963 resp_setup = tps .ftr .setup_listing (
13064 _DEVICE [device ],
131- File . UNKNOWN ,
65+ _FILE [ filetype ] ,
13266 f"{ directory } /*"
13367 )
13468 if resp_setup .error != GeoComCode .OK :
@@ -149,6 +83,11 @@ def get_directory_items(
14983 {
15084 "name" : name ,
15185 "size" : size ,
86+ "date" : (
87+ lastmodified .isoformat (sep = " " )
88+ if lastmodified is not None
89+ else ""
90+ ),
15291 "children" : []
15392 }
15493 )
@@ -163,6 +102,11 @@ def get_directory_items(
163102 {
164103 "name" : name ,
165104 "size" : size ,
105+ "date" : (
106+ lastmodified .isoformat (sep = " " )
107+ if lastmodified is not None
108+ else ""
109+ ),
166110 "children" : []
167111 }
168112 )
@@ -174,43 +118,55 @@ def get_directory_items(
174118 tps ,
175119 device ,
176120 f"{ directory } /{ item ['name' ]} " ,
121+ filetype ,
177122 depth = (depth - 1 ) if depth > 0 else - 1
178123 )
179124
180125 return output
181126
182127
183128_RE_DBX = compile (r"(?:.X\d{2})|.xcf" , IGNORECASE )
129+ _fmt_dir = ":open_file_folder: [bold blue]{name}[/] [bright_black]({count})"
130+ _fmt_likelydir = ":grey_question: [cyan]{name}"
131+ _fmt_text = ":pencil: [green]{name}"
132+ _fmt_img = ":city_sunset: [bright_magenta]{name}"
133+ _fmt_dbx = ":package: [red]{name}"
134+ _fmt_unkown = ":grey_question: {name}"
184135
185136
186137def format_tree_item (
187138 tree : FileTreeItem
188- ) -> str :
189- fmt_dir = ":open_file_folder: [bold blue]{name}"
190- fmt_likelydir = ":grey_question: [cyan]{name} [bright_black]({size})"
191- fmt_text = ":pencil: [green]{name} [bright_black]({size})"
192- fmt_img = ":framed_picture: [bright_magenta]{name} [bright_black]({size})"
193- fmt_dbx = ":package: [red]{name} [bright_black]({size})"
194- fmt_unkown = ":grey_question: {name} [bright_black]({size})"
195-
196- name = tree ["name" ]
197- if isinstance (tree ["size" ], int ):
198- tree ["size" ] = decimal (tree ["size" ])
139+ ) -> RenderableType :
199140
200141 if len (tree ["children" ]) > 0 :
201- return fmt_dir .format_map (tree )
202-
203- match os .path .splitext (name )[1 ].lower ():
204- case "" :
205- return fmt_likelydir .format_map (tree )
206- case ".jpg" | ".jpeg" | ".bmp" | ".dxf" | ".dwg" :
207- return fmt_img .format_map (tree )
208- case ".txt" | ".gsi" | ".xml" :
209- return fmt_text .format_map (tree )
210- case dbx if _RE_DBX .match (dbx ):
211- return fmt_dbx .format_map (tree )
212-
213- return fmt_unkown .format_map (tree )
142+ name = _fmt_dir .format (
143+ name = tree ["name" ],
144+ count = len (tree ["children" ])
145+ )
146+ else :
147+ match os .path .splitext (tree ["name" ])[1 ].lower ():
148+ case "" :
149+ name = _fmt_likelydir .format_map (tree )
150+ case ".jpg" | ".jpeg" | ".bmp" | ".dxf" | ".dwg" :
151+ name = _fmt_img .format_map (tree )
152+ case ".txt" | ".gsi" | ".xml" :
153+ name = _fmt_text .format_map (tree )
154+ case dbx if _RE_DBX .match (dbx ):
155+ name = _fmt_dbx .format_map (tree )
156+ case _:
157+ name = _fmt_unkown .format_map (tree )
158+
159+ grid = Table .grid (expand = True )
160+ grid .add_column ()
161+ grid .add_column (justify = "right" )
162+ grid .add_row (
163+ Text .from_markup (name ),
164+ Text (
165+ f"{ decimal (tree ['size' ]):>10.10s} { tree ['date' ]:>25.25s} " ,
166+ justify = "right"
167+ )
168+ )
169+ return grid
214170
215171
216172def build_file_tree (
@@ -236,6 +192,7 @@ def run_listing_tree(
236192 tps : GeoCom ,
237193 dev : str ,
238194 directory : str ,
195+ filetype : str | None ,
239196 depth : int = 1
240197) -> None :
241198 with progressbar (
@@ -250,18 +207,21 @@ def run_listing_tree(
250207 else dev .upper ()
251208 ),
252209 "size" : 0 ,
210+ "date" : "unknown" ,
253211 "children" : get_directory_items (
254212 bar ,
255213 tps ,
256214 dev ,
257215 directory ,
258- 1 if depth == 0 else depth
216+ filetype or "unknown" ,
217+ - 1 if depth == 0 else depth
259218 )
260219 }
261220 bar .finish ()
262221
263222 treeview = build_file_tree (tree )
264- rprint (treeview )
223+ console = Console (width = 120 )
224+ console .print (treeview )
265225
266226
267227def run_download (
@@ -343,8 +303,7 @@ def main_list(
343303 retry : int = 1 ,
344304 sync_after_timeout : bool = False ,
345305 device : str = "internal" ,
346- filetype : str = "unknown" ,
347- tree : bool = False ,
306+ filetype : str | None = None ,
348307 depth : int = 1
349308) -> None :
350309 with open_serial (
@@ -356,9 +315,6 @@ def main_list(
356315 ) as com :
357316 tps = GeoCom (com )
358317 try :
359- if not tree :
360- run_listing (tps , device , directory , filetype )
361- else :
362- run_listing_tree (tps , device , directory , depth )
318+ run_listing_tree (tps , device , directory , filetype , depth )
363319 finally :
364320 tps .ftr .abort_list ()
0 commit comments