vappman 0.6__py3-none-any.whl → 0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vappman/main.py +49 -34
- {vappman-0.6.dist-info → vappman-0.7.dist-info}/METADATA +13 -5
- vappman-0.7.dist-info/RECORD +9 -0
- {vappman-0.6.dist-info → vappman-0.7.dist-info}/WHEEL +1 -1
- vappman-0.6.dist-info/RECORD +0 -9
- {vappman-0.6.dist-info → vappman-0.7.dist-info}/LICENSE +0 -0
- {vappman-0.6.dist-info → vappman-0.7.dist-info}/entry_points.txt +0 -0
- {vappman-0.6.dist-info → vappman-0.7.dist-info}/top_level.txt +0 -0
vappman/main.py
CHANGED
|
@@ -6,7 +6,7 @@ Interactive, visual thin layer atop appman
|
|
|
6
6
|
# pylint: disable=broad-exception-caught,consider-using-with
|
|
7
7
|
# pylint: disable=too-many-instance-attributes,too-many-branches
|
|
8
8
|
# pylint: disable=too-many-return-statements,too-many-statements
|
|
9
|
-
|
|
9
|
+
# pylint: disable=consider-using-in
|
|
10
10
|
# pylint: disable=wrong-import-position,disable=wrong-import-order
|
|
11
11
|
# import VirtEnv
|
|
12
12
|
# VirtEnv.ensure_venv(__name__)
|
|
@@ -17,10 +17,7 @@ import re
|
|
|
17
17
|
import shutil
|
|
18
18
|
import subprocess
|
|
19
19
|
import traceback
|
|
20
|
-
import copy
|
|
21
|
-
import shutil
|
|
22
20
|
import curses as cs
|
|
23
|
-
from types import SimpleNamespace
|
|
24
21
|
from vappman.PowerWindow import Window, OptionSpinner
|
|
25
22
|
|
|
26
23
|
|
|
@@ -40,6 +37,7 @@ class Vappman:
|
|
|
40
37
|
other = 'airbou/qscU'
|
|
41
38
|
other_keys = set(ord(x) for x in other)
|
|
42
39
|
other_keys.add(cs.KEY_ENTER)
|
|
40
|
+
other_keys.add(27) # ESCAPE
|
|
43
41
|
other_keys.add(10) # another form of ENTER
|
|
44
42
|
self.opts = spin.default_obj
|
|
45
43
|
|
|
@@ -115,6 +113,7 @@ class Vappman:
|
|
|
115
113
|
' U - update ALL installed apps',
|
|
116
114
|
' / - filter apps',
|
|
117
115
|
' ENTER = install, remove, or return from help',
|
|
116
|
+
' ESC = clear filter and jump to top',
|
|
118
117
|
'CONTEXT SENSITIVE:',
|
|
119
118
|
' i - install uninstalled app',
|
|
120
119
|
' r - remove installed app',
|
|
@@ -135,11 +134,11 @@ class Vappman:
|
|
|
135
134
|
for app, line in self.installs.items():
|
|
136
135
|
if app in self.apps:
|
|
137
136
|
line = self.apps[app]
|
|
138
|
-
if wanted(line):
|
|
137
|
+
if wanted(line[2:]):
|
|
139
138
|
line = '✔✔✔' + line[1:]
|
|
140
139
|
self.win.add_body(line)
|
|
141
140
|
for app, line in self.apps.items():
|
|
142
|
-
if app not in self.installs and wanted(line):
|
|
141
|
+
if app not in self.installs and wanted(line[2:]):
|
|
143
142
|
self.win.add_body(line)
|
|
144
143
|
self.win.render()
|
|
145
144
|
|
|
@@ -149,15 +148,17 @@ class Vappman:
|
|
|
149
148
|
def get_keys_line(self):
|
|
150
149
|
""" TBD """
|
|
151
150
|
# EXPAND
|
|
152
|
-
|
|
153
|
-
line = 'KEYS:'
|
|
151
|
+
line = ''
|
|
154
152
|
for key, verb in self.actions.items():
|
|
155
|
-
|
|
153
|
+
if key[0] == verb[0]:
|
|
154
|
+
line += f' {verb}'
|
|
155
|
+
else:
|
|
156
|
+
line += f' {key}:{verb}'
|
|
156
157
|
# or EXPAND
|
|
157
|
-
line += f' ?:help
|
|
158
|
+
line += f' ?:help quit about sync clean Upd /{self.prev_filter} '
|
|
158
159
|
# for action in self.actions:
|
|
159
160
|
# line += f' {action[0]}:{action}'
|
|
160
|
-
return line
|
|
161
|
+
return line[1:]
|
|
161
162
|
|
|
162
163
|
def get_actions(self, line):
|
|
163
164
|
""" Determine the type of the current line and available commands."""
|
|
@@ -185,27 +186,30 @@ class Vappman:
|
|
|
185
186
|
"""
|
|
186
187
|
this = Vappman.singleton
|
|
187
188
|
this.pick_app, this.actions = this.get_actions(line)
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
189
|
+
header = this.get_keys_line()
|
|
190
|
+
# ASSUME line ends in /....
|
|
191
|
+
parts = header.split('/', maxsplit=1)
|
|
192
|
+
wds = parts[0].split()
|
|
193
|
+
this.win.head.pad.move(0, 0)
|
|
194
|
+
for wd in wds:
|
|
195
|
+
if wd:
|
|
196
|
+
this.win.add_header(wd[0], attr=cs.A_BOLD|cs.A_UNDERLINE, resume=True)
|
|
197
|
+
if wd[1:]:
|
|
198
|
+
this.win.add_header(wd[1:] + ' ', resume=True)
|
|
199
|
+
|
|
200
|
+
this.win.add_header('/', attr=cs.A_BOLD+cs.A_UNDERLINE, resume=True)
|
|
201
|
+
if len(parts) > 1 and parts[1]:
|
|
202
|
+
this.win.add_header(f'{parts[1]}', resume=True)
|
|
203
|
+
_, col = this.win.head.pad.getyx()
|
|
204
|
+
pad = ' ' * (this.win.get_pad_width()-col)
|
|
205
|
+
this.win.add_header(pad, resume=True)
|
|
191
206
|
return line
|
|
192
|
-
|
|
193
|
-
# suffix = ''
|
|
194
|
-
# for action in actions:
|
|
195
|
-
# suffix += f' {action[0]}:{action}'
|
|
196
|
-
# block_char = "\u2588"
|
|
197
|
-
# suffix = f'{block_char*5} {suffix}'
|
|
198
|
-
# over = len(line) + len(suffix) - this.win.get_pad_width()
|
|
199
|
-
# if over < 0:
|
|
200
|
-
# line += ' '*(-over)
|
|
201
|
-
# elif over > 0:
|
|
202
|
-
# line = line[0:-over]
|
|
203
|
-
|
|
204
|
-
# return line + suffix
|
|
207
|
+
|
|
205
208
|
def run_appman(self, cmd):
|
|
209
|
+
""" Run a 'appman' command """
|
|
206
210
|
Window.stop_curses()
|
|
207
211
|
os.system(f'clear; stty sane; {cmd};'
|
|
208
|
-
+ ' /bin/echo -e "\n\n===== Press ENTER for menu ====> \c"; read FOO')
|
|
212
|
+
+ r' /bin/echo -e "\n\n===== Press ENTER for menu ====> \c"; read FOO')
|
|
209
213
|
self.installs = self.get_installed()
|
|
210
214
|
Window._start_curses()
|
|
211
215
|
|
|
@@ -217,7 +221,7 @@ class Vappman:
|
|
|
217
221
|
if self.opts.help_mode:
|
|
218
222
|
self.opts.help_mode = False
|
|
219
223
|
return True
|
|
220
|
-
|
|
224
|
+
if self.pick_is_installed:
|
|
221
225
|
key = ord('r') # removed installed app
|
|
222
226
|
else:
|
|
223
227
|
key = ord('i') # install uninstalled app
|
|
@@ -226,6 +230,12 @@ class Vappman:
|
|
|
226
230
|
value = self.spin.do_key(key, self.win)
|
|
227
231
|
return value
|
|
228
232
|
|
|
233
|
+
if key == 27: # ESCAPE
|
|
234
|
+
self.prev_filter = ''
|
|
235
|
+
self.filter = None
|
|
236
|
+
self.win.pick_pos = 0
|
|
237
|
+
return None
|
|
238
|
+
|
|
229
239
|
if key == ord('q'):
|
|
230
240
|
self.win.stop_curses()
|
|
231
241
|
os.system('clear; stty sane')
|
|
@@ -252,11 +262,12 @@ class Vappman:
|
|
|
252
262
|
if key == ord('u'):
|
|
253
263
|
self.run_appman(f'appman update {self.pick_app}')
|
|
254
264
|
if key == ord('U'):
|
|
255
|
-
self.run_appman(
|
|
265
|
+
self.run_appman('appman update')
|
|
256
266
|
# EXPAND
|
|
257
267
|
|
|
258
268
|
if key == ord('/'):
|
|
259
269
|
# pylint: disable=protected-access
|
|
270
|
+
start_filter = self.prev_filter
|
|
260
271
|
|
|
261
272
|
prefix = ''
|
|
262
273
|
while True:
|
|
@@ -266,18 +277,22 @@ class Vappman:
|
|
|
266
277
|
pattern.strip()
|
|
267
278
|
if not pattern:
|
|
268
279
|
self.filter = None
|
|
269
|
-
|
|
280
|
+
break
|
|
270
281
|
|
|
271
282
|
try:
|
|
272
283
|
if re.match(r'^[\-\w\s]*$', pattern):
|
|
273
284
|
words = pattern.split()
|
|
274
|
-
self.filter = re.compile(r'\b' + r'
|
|
275
|
-
|
|
285
|
+
self.filter = re.compile(r'\b' + r'(|.*\b)'.join(words), re.IGNORECASE)
|
|
286
|
+
break
|
|
276
287
|
self.filter = re.compile(pattern, re.IGNORECASE)
|
|
277
|
-
|
|
288
|
+
break
|
|
278
289
|
except Exception:
|
|
279
290
|
prefix = 'Bad regex: '
|
|
280
291
|
|
|
292
|
+
if start_filter != self.prev_filter:
|
|
293
|
+
# when filter changes, move to top
|
|
294
|
+
self.win.pick_pos = 0
|
|
295
|
+
|
|
281
296
|
return None
|
|
282
297
|
return None
|
|
283
298
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: vappman
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7
|
|
4
4
|
Summary: A visual wrapper for appman
|
|
5
5
|
Author-email: Joe Defen <joedef@google.com>
|
|
6
6
|
License: MIT
|
|
@@ -56,10 +56,16 @@ But it does NOT cover:
|
|
|
56
56
|
* Installed apps have prefix '✔✔✔' (i.e., three checks).
|
|
57
57
|
* Uninstalled apps have prefix '◆' (i.e., a solid diamond).
|
|
58
58
|
* Enter `/` to enter a "filter" for installed/uninstalled apps, if you wish.
|
|
59
|
-
* If you enter plain ole "words", then those words must match
|
|
60
|
-
of the apps
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
* If you enter plain ole "words", then those words must match:
|
|
60
|
+
* the start of words on the apps line (in order, but not contiguously) and/or
|
|
61
|
+
* the start of the remainder of the previous word match
|
|
62
|
+
(i.e., `/bit fight` matches `bitfighter`).
|
|
63
|
+
* Or you can enter an regular expression acceptable to python; e.g.,
|
|
64
|
+
* `^` matches the line starting with the app name
|
|
65
|
+
* `\b` matches a word boundary; and so forth.
|
|
66
|
+
* NOTES:
|
|
67
|
+
* `ESC` clears the filter and jumps to the top of the listing.
|
|
68
|
+
* Each time the filter is changed, the position jumps to the top of the listing.
|
|
63
69
|
* Use `i` to install apps, and `r` to remove apps. When you install or remove an app, `appman` drops out of `curses` mode, runs the `appman` command so you can see the result, and then prompts your to hit ENTER to return to `vappman.
|
|
64
70
|
|
|
65
71
|
## Example Screenshot
|
|
@@ -75,4 +81,6 @@ NOTES: in this example:
|
|
|
75
81
|
all the filtered apps; otherwise, the decoration suggests where you are in the
|
|
76
82
|
partial view of the filtered apps.
|
|
77
83
|
* the matching installed app has the '✔✔✔' prefix.
|
|
84
|
+
* the fixed top line shows some of the available action keys (e.g., `q` quits the app)
|
|
85
|
+
* use `?` to open the help screen describing all keys (including navigation)
|
|
78
86
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
vappman/PowerWindow.py,sha256=OLCX-RkbJZ2wwaY7M-4Eo9PQuR95TWrGNIY8DdVRpsE,28567
|
|
2
|
+
vappman/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
vappman/main.py,sha256=8I97lvSqpkPzQ51q_NDPb6dL18Th-ZHm_PRTT6BE9Ec,11105
|
|
4
|
+
vappman-0.7.dist-info/LICENSE,sha256=qB9OdnyyF6WYHiEIXVm0rOSdcf8e2ctorrtWs6CC5lU,1062
|
|
5
|
+
vappman-0.7.dist-info/METADATA,sha256=_xoExbsd16j5PAWgJrvaSw3uiW18aWY8tRfeJ53HLnM,4360
|
|
6
|
+
vappman-0.7.dist-info/WHEEL,sha256=cpQTJ5IWu9CdaPViMhC9YzF8gZuS5-vlfoFihTBC86A,91
|
|
7
|
+
vappman-0.7.dist-info/entry_points.txt,sha256=7_1MiUvkCJoElLePOCJYqhkQN4xmadBRQCKupOwzt90,46
|
|
8
|
+
vappman-0.7.dist-info/top_level.txt,sha256=5_Gb5oZh7s2-i62gLXZ6INVALAV9D0-yqh0TvNqpPC4,8
|
|
9
|
+
vappman-0.7.dist-info/RECORD,,
|
vappman-0.6.dist-info/RECORD
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
vappman/PowerWindow.py,sha256=OLCX-RkbJZ2wwaY7M-4Eo9PQuR95TWrGNIY8DdVRpsE,28567
|
|
2
|
-
vappman/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
vappman/main.py,sha256=rSWpH_l_IgH3jR4HSG-H8lvmuuAZWStPo-AMtSIsZYY,10483
|
|
4
|
-
vappman-0.6.dist-info/LICENSE,sha256=qB9OdnyyF6WYHiEIXVm0rOSdcf8e2ctorrtWs6CC5lU,1062
|
|
5
|
-
vappman-0.6.dist-info/METADATA,sha256=pWiQZo-R_ePgEX3Yz9oAcNty2XBmYCArV--3ErQd_HI,3850
|
|
6
|
-
vappman-0.6.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
7
|
-
vappman-0.6.dist-info/entry_points.txt,sha256=7_1MiUvkCJoElLePOCJYqhkQN4xmadBRQCKupOwzt90,46
|
|
8
|
-
vappman-0.6.dist-info/top_level.txt,sha256=5_Gb5oZh7s2-i62gLXZ6INVALAV9D0-yqh0TvNqpPC4,8
|
|
9
|
-
vappman-0.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|