@@ -69,25 +69,21 @@ def parse_to_pyobj(text: str, jpath: Optional[str]) -> tuple[Any, str]:
69
69
return subelements , fmt
70
70
71
71
72
- def output (output_fp : IO , text : str , fmt : str , cp2clip : bool ):
73
- # copy the result to clipboard
74
- if cp2clip :
75
- pyperclip .copy (text )
76
- print_inf ('result copied to clipboard.' )
77
- return
78
- elif stdout .isatty ():
79
- # highlight the text when output to TTY divice
80
- Lexer = {'json' : JsonLexer , 'toml' : TOMLLexer , 'yaml' : YamlLexer }[fmt ]
81
- colored_text = highlight (text , Lexer (), TerminalFormatter ())
82
- win_w , win_h = get_terminal_size ()
83
- # use pager when line-hight > screen hight or
84
- if text .count ('\n ' ) >= win_h or len (text ) > win_w * (win_h - 1 ):
85
- with patch ("sys.stdin.isatty" , lambda * _ : True ):
86
- pager (colored_text )
72
+ def get_overview (py_obj : Any ):
73
+ def clip_value (value : Any ):
74
+ if isinstance (value , str ):
75
+ return '...'
76
+ elif isinstance (value , (list , tuple )):
77
+ return []
78
+ elif isinstance (value , dict ):
79
+ return {k : clip_value (v ) for k , v in value .items ()}
87
80
else :
88
- output_fp .write (colored_text )
81
+ return value
82
+
83
+ if isinstance (py_obj , list ):
84
+ return [clip_value (py_obj [0 ])]
89
85
else :
90
- output_fp . write ( text )
86
+ return clip_value ( py_obj )
91
87
92
88
93
89
def format_to_text (py_obj : Any , fmt : str , * ,
@@ -104,36 +100,62 @@ def format_to_text(py_obj: Any, fmt: str, *,
104
100
elif fmt == 'toml' :
105
101
if not isinstance (py_obj , dict ):
106
102
msg = 'the pyobj must be a Mapping when format to toml'
107
- print_err (msg )
108
103
raise ParseError (msg )
109
104
return toml .dumps (py_obj )
110
105
111
- elif fmt == 'toml ' :
106
+ elif fmt == 'yaml ' :
112
107
return yaml .safe_dump (py_obj , allow_unicode = not escape , indent = indent ,
113
108
sort_keys = sort_keys )
114
109
115
110
else :
116
111
raise ParseError ('Unknow format' )
117
112
118
113
119
- def process (input_fp : IO , jpath : Optional [str ], * ,
120
- overwrite : bool , cp2clip : bool , compact : bool ,
121
- escape : bool , indent : int , sort_keys : bool ):
114
+ def output (output_fp : IO , text : str , fmt : str , cp2clip : bool ):
115
+ # copy the result to clipboard
116
+ if cp2clip :
117
+ pyperclip .copy (text )
118
+ print_inf ('result copied to clipboard.' )
119
+ return
120
+ elif stdout .isatty ():
121
+ # highlight the text when output to TTY divice
122
+ Lexer = {'json' : JsonLexer , 'toml' : TOMLLexer , 'yaml' : YamlLexer }[fmt ]
123
+ colored_text = highlight (text , Lexer (), TerminalFormatter ())
124
+ win_w , win_h = get_terminal_size ()
125
+ # use pager when line-hight > screen hight or
126
+ if text .count ('\n ' ) >= win_h or len (text ) > win_w * (win_h - 1 ):
127
+ with patch ("sys.stdin.isatty" , lambda * _ : True ):
128
+ pager (colored_text )
129
+ else :
130
+ output_fp .write (colored_text )
131
+ else :
132
+ output_fp .seek (0 )
133
+ output_fp .truncate ()
134
+ output_fp .write (text )
135
+
136
+
137
+ def process (input_fp : IO , jpath : Optional [str ], to_format : Optional [str ], * ,
138
+ compact : bool , cp2clip : bool , escape : bool , indent : int ,
139
+ overview : bool , overwrite : bool , sort_keys : bool ):
122
140
# parse and format
123
141
input_text = input_fp .read ()
124
142
py_obj , fmt = parse_to_pyobj (input_text , jpath )
125
- formated_text = format_to_text (py_obj , fmt ,
143
+
144
+ if overview :
145
+ py_obj = get_overview (py_obj )
146
+
147
+ to_format = to_format or fmt
148
+ formated_text = format_to_text (py_obj , to_format ,
126
149
compact = compact , escape = escape ,
127
150
indent = indent , sort_keys = sort_keys )
128
151
152
+ # output the result
129
153
if input_fp .name == '<stdin>' or not overwrite :
130
154
output_fp = stdout
131
155
else :
132
156
# truncate file to zero length before overwrite
133
- input_fp .seek (0 )
134
- input_fp .truncate ()
135
157
output_fp = input_fp
136
- output (output_fp , formated_text , fmt , cp2clip )
158
+ output (output_fp , formated_text , to_format , cp2clip )
137
159
138
160
139
161
def parse_cmdline_args (args : Optional [Sequence [str ]] = None ):
@@ -144,11 +166,12 @@ def parse_cmdline_args(args: Optional[Sequence[str]] = None):
144
166
help = 'copy the result to clipboard' )
145
167
parser .add_argument ('-e' , dest = 'escape' , action = 'store_true' ,
146
168
help = 'escape non-ASCII characters' )
147
- parser .add_argument ('-f' , dest = 'format' , default = 'json' ,
148
- choices = ['json' , 'toml' , 'yaml' ],
169
+ parser .add_argument ('-f' , dest = 'format' , choices = ['json' , 'toml' , 'yaml' ],
149
170
help = 'the format to output ' '(default: %(default)s)' )
150
171
parser .add_argument ('-i' , dest = 'indent' , type = int , default = 2 ,
151
172
help = 'number of spaces for indentation (default: %(default)s)' )
173
+ parser .add_argument ('-o' , dest = 'overview' , action = 'store_true' ,
174
+ help = 'show data structure overview' )
152
175
parser .add_argument ('-O' , dest = 'overwrite' , action = 'store_true' ,
153
176
help = 'overwrite the formated text to original file' )
154
177
parser .add_argument ('-p' , dest = 'jsonpath' , type = str ,
@@ -176,10 +199,16 @@ def main():
176
199
try :
177
200
# read from file
178
201
input_fp = open (file , 'r+' ) if isinstance (file , str ) else file
179
- process (input_fp , args .jsonpath ,
180
- overwrite = args .overwrite , cp2clip = cp2clip ,
181
- compact = args .compact , escape = args .escape ,
182
- indent = args .indent , sort_keys = args .sort_keys )
202
+ process (input_fp ,
203
+ args .jsonpath ,
204
+ args .format ,
205
+ compact = args .compact ,
206
+ cp2clip = cp2clip ,
207
+ escape = args .escape ,
208
+ indent = args .indent ,
209
+ overview = args .overview ,
210
+ overwrite = args .overwrite ,
211
+ sort_keys = args .sort_keys )
183
212
except ParseError as err :
184
213
print_err (err )
185
214
except FileNotFoundError :
0 commit comments