omdev 0.0.0.dev486__py3-none-any.whl → 0.0.0.dev500__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.
Potentially problematic release.
This version of omdev might be problematic. Click here for more details.
- omdev/.omlish-manifests.json +1 -1
- omdev/README.md +51 -0
- omdev/__about__.py +4 -2
- omdev/ci/cli.py +1 -1
- omdev/cli/clicli.py +37 -7
- omdev/dataclasses/cli.py +1 -1
- omdev/interp/cli.py +1 -1
- omdev/interp/types.py +3 -2
- omdev/interp/uv/provider.py +36 -0
- omdev/manifests/main.py +1 -1
- omdev/packaging/revisions.py +1 -1
- omdev/py/tools/pipdepup.py +150 -93
- omdev/pyproject/cli.py +1 -1
- omdev/pyproject/pkg.py +1 -1
- omdev/pyproject/reqs.py +8 -7
- omdev/pyproject/tools/aboutdeps.py +5 -0
- omdev/scripts/ci.py +361 -25
- omdev/scripts/interp.py +43 -8
- omdev/scripts/lib/logs.py +117 -21
- omdev/scripts/pyproject.py +415 -39
- omdev/tools/git/cli.py +43 -13
- omdev/tools/json/formats.py +2 -0
- omdev/tools/jsonview/cli.py +19 -61
- omdev/tools/jsonview/resources/jsonview.html.j2 +43 -0
- omdev/tools/pawk/README.md +195 -0
- omdev/tui/apps/edit/main.py +5 -1
- omdev/tui/apps/irc/app.py +28 -20
- omdev/tui/apps/irc/commands.py +1 -1
- omdev/tui/rich/__init__.py +12 -0
- omdev/tui/textual/__init__.py +41 -2
- omdev/tui/textual/app2.py +6 -1
- omdev/tui/textual/debug/__init__.py +10 -0
- omdev/tui/textual/debug/dominfo.py +151 -0
- omdev/tui/textual/debug/screen.py +24 -0
- omdev/tui/textual/devtools.py +187 -0
- omdev/tui/textual/logging2.py +20 -0
- omdev/tui/textual/types.py +45 -0
- {omdev-0.0.0.dev486.dist-info → omdev-0.0.0.dev500.dist-info}/METADATA +10 -6
- {omdev-0.0.0.dev486.dist-info → omdev-0.0.0.dev500.dist-info}/RECORD +43 -34
- {omdev-0.0.0.dev486.dist-info → omdev-0.0.0.dev500.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev486.dist-info → omdev-0.0.0.dev500.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev486.dist-info → omdev-0.0.0.dev500.dist-info}/licenses/LICENSE +0 -0
- {omdev-0.0.0.dev486.dist-info → omdev-0.0.0.dev500.dist-info}/top_level.txt +0 -0
omdev/tools/git/cli.py
CHANGED
|
@@ -90,7 +90,12 @@ def get_first_commit_of_day(rev: str) -> str | None:
|
|
|
90
90
|
class Cli(ap.Cli):
|
|
91
91
|
@dc.dataclass(frozen=True, kw_only=True)
|
|
92
92
|
class Config:
|
|
93
|
-
|
|
93
|
+
@dc.dataclass(frozen=True, kw_only=True)
|
|
94
|
+
class MessageGenerator:
|
|
95
|
+
name: str
|
|
96
|
+
config: ta.Mapping[str, ta.Any] | None = None
|
|
97
|
+
|
|
98
|
+
message_generator: str | MessageGenerator | None = None
|
|
94
99
|
|
|
95
100
|
_config_file_path_arg: ta.Optional[str] = ap.arg_('-c', '--config-file-path', nargs='?')
|
|
96
101
|
|
|
@@ -280,6 +285,35 @@ class Cli(ap.Cli):
|
|
|
280
285
|
|
|
281
286
|
# Lazy helpers
|
|
282
287
|
|
|
288
|
+
def _make_git_message_generator(
|
|
289
|
+
self,
|
|
290
|
+
*,
|
|
291
|
+
name: str | None = None,
|
|
292
|
+
cwd: str | None = None,
|
|
293
|
+
) -> GitMessageGenerator:
|
|
294
|
+
cls: type[GitMessageGenerator] = TimestampGitMessageGenerator
|
|
295
|
+
kw: dict[str, ta.Any] = {}
|
|
296
|
+
|
|
297
|
+
if name is None:
|
|
298
|
+
if cwd is None:
|
|
299
|
+
cwd = os.getcwd()
|
|
300
|
+
|
|
301
|
+
cfg = self.load_config(cwd).message_generator
|
|
302
|
+
if cfg is None:
|
|
303
|
+
pass
|
|
304
|
+
elif isinstance(cfg, str):
|
|
305
|
+
name = cfg
|
|
306
|
+
elif isinstance(cfg, Cli.Config.MessageGenerator):
|
|
307
|
+
name = cfg.name
|
|
308
|
+
kw.update(cfg.config or {})
|
|
309
|
+
else:
|
|
310
|
+
raise TypeError(cfg)
|
|
311
|
+
|
|
312
|
+
if name is not None:
|
|
313
|
+
cls = load_message_generator_manifests_map()[name].load_cls()
|
|
314
|
+
|
|
315
|
+
return cls(**kw)
|
|
316
|
+
|
|
283
317
|
@ap.cmd(
|
|
284
318
|
ap.arg('-g', '--message-generator', nargs='?'),
|
|
285
319
|
ap.arg('dir', nargs='*'),
|
|
@@ -292,12 +326,10 @@ class Cli(ap.Cli):
|
|
|
292
326
|
if not (st.has_staged or st.has_dirty):
|
|
293
327
|
return
|
|
294
328
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
mg_cls = load_message_generator_manifests_map()[mg_name].load_cls()
|
|
300
|
-
mg = mg_cls()
|
|
329
|
+
mg = self._make_git_message_generator(
|
|
330
|
+
name=self.args.message_generator,
|
|
331
|
+
cwd=cwd,
|
|
332
|
+
)
|
|
301
333
|
|
|
302
334
|
mgr = mg.generate_commit_message(GitMessageGenerator.GenerateCommitMessageArgs(
|
|
303
335
|
cwd=cwd,
|
|
@@ -338,12 +370,10 @@ class Cli(ap.Cli):
|
|
|
338
370
|
msg = self.args.message
|
|
339
371
|
|
|
340
372
|
else:
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
mg_cls = load_message_generator_manifests_map()[mg_name].load_cls()
|
|
346
|
-
mg = mg_cls()
|
|
373
|
+
mg = self._make_git_message_generator(
|
|
374
|
+
name=self.args.message_generator,
|
|
375
|
+
cwd=cwd,
|
|
376
|
+
)
|
|
347
377
|
|
|
348
378
|
mgr = mg.generate_commit_message(GitMessageGenerator.GenerateCommitMessageArgs(
|
|
349
379
|
cwd=cwd,
|
omdev/tools/json/formats.py
CHANGED
omdev/tools/jsonview/cli.py
CHANGED
|
@@ -3,7 +3,7 @@ TODO:
|
|
|
3
3
|
- read from stdin
|
|
4
4
|
- evaluate jmespath on server using extended engine
|
|
5
5
|
- integrate with json tool
|
|
6
|
-
- use omlish server
|
|
6
|
+
- use omlish server
|
|
7
7
|
- vendor deps, serve local
|
|
8
8
|
- update to https://github.com/josdejong/svelte-jsoneditor
|
|
9
9
|
"""
|
|
@@ -19,61 +19,22 @@ import webbrowser
|
|
|
19
19
|
|
|
20
20
|
from omlish import check
|
|
21
21
|
from omlish import lang
|
|
22
|
+
from omlish.sockets.ports import get_available_port
|
|
23
|
+
from omlish.text import minja
|
|
22
24
|
|
|
23
25
|
|
|
24
26
|
##
|
|
25
27
|
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
<head>
|
|
32
|
-
<meta charset="UTF-8">
|
|
33
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
34
|
-
<title>JSON Viewer</title>
|
|
35
|
-
<link
|
|
36
|
-
href="https://cdn.jsdelivr.net/npm/jsoneditor/dist/jsoneditor.min.css"
|
|
37
|
-
rel="stylesheet"
|
|
38
|
-
type="text/css"
|
|
39
|
-
>
|
|
40
|
-
<style>
|
|
41
|
-
{css_src}
|
|
42
|
-
</style>
|
|
43
|
-
</head>
|
|
44
|
-
|
|
45
|
-
<body>
|
|
46
|
-
<div class="input-area">
|
|
47
|
-
<label for="jmespath-input">JMESPath:</label>
|
|
48
|
-
<input
|
|
49
|
-
type="text"
|
|
50
|
-
id="jmespath-input"
|
|
51
|
-
list="jmespath-history"
|
|
52
|
-
placeholder="Enter JMESPath expression..."
|
|
53
|
-
autocomplete="off"
|
|
54
|
-
>
|
|
55
|
-
<datalist id="jmespath-history"></datalist>
|
|
56
|
-
<span id="error-message"></span>
|
|
57
|
-
</div>
|
|
58
|
-
<div id="jsoneditor"></div>
|
|
59
|
-
|
|
60
|
-
<script src="https://cdn.jsdelivr.net/npm/jsoneditor@10.2.0/dist/jsoneditor.min.js"></script>
|
|
61
|
-
<script src="https://cdn.jsdelivr.net/npm/jmespath@0.16.0/jmespath.min.js"></script>
|
|
62
|
-
<script>
|
|
63
|
-
const originalJsonData = {json_data};
|
|
64
|
-
</script>
|
|
65
|
-
<script>
|
|
66
|
-
{js_src}
|
|
67
|
-
</script>
|
|
68
|
-
</body>
|
|
69
|
-
|
|
70
|
-
</html>
|
|
71
|
-
"""
|
|
29
|
+
@lang.cached_function
|
|
30
|
+
def html_template() -> minja.MinjaTemplate:
|
|
31
|
+
src = lang.get_relative_resources('resources', globals=globals())['jsonview.html.j2'].read_text()
|
|
32
|
+
return minja.compile_minja_template(src, ['ctx'])
|
|
72
33
|
|
|
73
34
|
|
|
74
35
|
def view_json(
|
|
75
36
|
filepath: str,
|
|
76
|
-
port: int,
|
|
37
|
+
port: int | None,
|
|
77
38
|
*,
|
|
78
39
|
mode: ta.Literal['jsonl', 'json5', 'json', None] = None,
|
|
79
40
|
) -> None:
|
|
@@ -120,15 +81,18 @@ def view_json(
|
|
|
120
81
|
self.send_response(200)
|
|
121
82
|
self.send_header('Content-type', 'text/html')
|
|
122
83
|
self.end_headers()
|
|
123
|
-
html_content =
|
|
124
|
-
css_src=css_src,
|
|
125
|
-
js_src=js_src,
|
|
84
|
+
html_content = html_template()(ctx=dict(
|
|
85
|
+
css_src=css_src.strip(),
|
|
86
|
+
js_src=js_src.strip(),
|
|
126
87
|
json_data=json_string,
|
|
127
|
-
)
|
|
88
|
+
))
|
|
128
89
|
self.wfile.write(html_content.encode('utf-8'))
|
|
129
90
|
else:
|
|
130
91
|
super().do_GET()
|
|
131
92
|
|
|
93
|
+
if port is None:
|
|
94
|
+
port = get_available_port()
|
|
95
|
+
|
|
132
96
|
handler_cls = JsonViewerHttpRequestHandler
|
|
133
97
|
with socketserver.TCPServer(('127.0.0.1', port), handler_cls) as httpd:
|
|
134
98
|
url = f'http://127.0.0.1:{port}'
|
|
@@ -150,18 +114,12 @@ def _main() -> None:
|
|
|
150
114
|
description='Launch a web-based JSON viewer with JMESPath transformations.',
|
|
151
115
|
formatter_class=argparse.RawTextHelpFormatter,
|
|
152
116
|
)
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
)
|
|
157
|
-
parser.add_argument(
|
|
158
|
-
'-p', '--port',
|
|
159
|
-
type=int,
|
|
160
|
-
default=(default_port := 8999),
|
|
161
|
-
help=f'The port to run the web server on. Defaults to {default_port}.',
|
|
162
|
-
)
|
|
117
|
+
|
|
118
|
+
parser.add_argument('filepath')
|
|
119
|
+
parser.add_argument('-p', '--port', type=int)
|
|
163
120
|
parser.add_argument('-l', '--lines', action='store_true')
|
|
164
121
|
parser.add_argument('-5', '--five', action='store_true')
|
|
122
|
+
|
|
165
123
|
args = parser.parse_args()
|
|
166
124
|
|
|
167
125
|
check.state(not (args.lines and args.five))
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>JSON Viewer</title>
|
|
8
|
+
<link
|
|
9
|
+
href="https://cdn.jsdelivr.net/npm/jsoneditor/dist/jsoneditor.min.css"
|
|
10
|
+
rel="stylesheet"
|
|
11
|
+
type="text/css"
|
|
12
|
+
>
|
|
13
|
+
<style>
|
|
14
|
+
{{ ctx['css_src'] }}
|
|
15
|
+
</style>
|
|
16
|
+
</head>
|
|
17
|
+
|
|
18
|
+
<body>
|
|
19
|
+
<div class="input-area">
|
|
20
|
+
<label for="jmespath-input">JMESPath:</label>
|
|
21
|
+
<input
|
|
22
|
+
type="text"
|
|
23
|
+
id="jmespath-input"
|
|
24
|
+
list="jmespath-history"
|
|
25
|
+
placeholder="Enter JMESPath expression..."
|
|
26
|
+
autocomplete="off"
|
|
27
|
+
>
|
|
28
|
+
<datalist id="jmespath-history"></datalist>
|
|
29
|
+
<span id="error-message"></span>
|
|
30
|
+
</div>
|
|
31
|
+
<div id="jsoneditor"></div>
|
|
32
|
+
|
|
33
|
+
<script src="https://cdn.jsdelivr.net/npm/jsoneditor@10.2.0/dist/jsoneditor.min.js"></script>
|
|
34
|
+
<script src="https://cdn.jsdelivr.net/npm/jmespath@0.16.0/jmespath.min.js"></script>
|
|
35
|
+
<script>
|
|
36
|
+
const originalJsonData = {{ ctx['json_data'] }};
|
|
37
|
+
</script>
|
|
38
|
+
<script>
|
|
39
|
+
{{ ctx['js_src'] }}
|
|
40
|
+
</script>
|
|
41
|
+
</body>
|
|
42
|
+
|
|
43
|
+
</html>
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
[From alecthomas/pawk](https://github.com/alecthomas/pawk/blob/d60f78399e8a01857ebd73415a00e7eb424043ab/pawk.py)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
PAWK - A Python line processor (like AWK)
|
|
6
|
+
|
|
7
|
+
PAWK aims to bring the full power of Python to AWK-like line-processing.
|
|
8
|
+
|
|
9
|
+
Here are some quick examples to show some of the advantages of pawk over AWK.
|
|
10
|
+
|
|
11
|
+
The first example transforms `/etc/hosts` into a JSON map of host to IP:
|
|
12
|
+
|
|
13
|
+
cat /etc/hosts | pawk -B 'd={}' -E 'json.dumps(d)' '!/^#/ d[f[1]] = f[0]'
|
|
14
|
+
|
|
15
|
+
Breaking this down:
|
|
16
|
+
|
|
17
|
+
1. `-B 'd={}'` is a begin statement initializing a dictionary, executed once before processing begins.
|
|
18
|
+
2. `-E 'json.dumps(d)'` is an end statement expression, producing the JSON representation of the dictionary `d`.
|
|
19
|
+
3. `!/^#/` tells pawk to match any line *not* beginning with `#`.
|
|
20
|
+
4. `d[f[1]] = f[0]` adds a dictionary entry where the key is the second field in the line (the first hostname) and the
|
|
21
|
+
value is the first field (the IP address).
|
|
22
|
+
|
|
23
|
+
And another example showing how to bzip2-compress + base64-encode a file:
|
|
24
|
+
|
|
25
|
+
cat pawk.py | pawk -E 'base64.encodestring(bz2.compress(t))'
|
|
26
|
+
|
|
27
|
+
### AWK example translations
|
|
28
|
+
|
|
29
|
+
Most basic AWK constructs are available. You can find more idiomatic examples below in the example section, but here are
|
|
30
|
+
a bunch of awk commands and their equivalent pawk commands to get started with:
|
|
31
|
+
|
|
32
|
+
Print lines matching a pattern:
|
|
33
|
+
|
|
34
|
+
ls -l / | awk '/etc/'
|
|
35
|
+
ls -l / | pawk '/etc/'
|
|
36
|
+
|
|
37
|
+
Print lines *not* matching a pattern:
|
|
38
|
+
|
|
39
|
+
ls -l / | awk '!/etc/'
|
|
40
|
+
ls -l / | pawk '!/etc/'
|
|
41
|
+
|
|
42
|
+
Field slicing and dicing (here pawk wins because of Python's array slicing):
|
|
43
|
+
|
|
44
|
+
ls -l / | awk '/etc/ {print $5, $6, $7, $8, $9}'
|
|
45
|
+
ls -l / | pawk '/etc/ f[4:]'
|
|
46
|
+
|
|
47
|
+
Begin and end actions (in this case, summing the sizes of all files):
|
|
48
|
+
|
|
49
|
+
ls -l | awk 'BEGIN {c = 0} {c += $5} END {print c}'
|
|
50
|
+
ls -l | pawk -B 'c = 0' -E 'c' 'c += int(f[4])'
|
|
51
|
+
|
|
52
|
+
Print files where a field matches a numeric expression (in this case where files are > 1024 bytes):
|
|
53
|
+
|
|
54
|
+
ls -l | awk '$5 > 1024'
|
|
55
|
+
ls -l | pawk 'int(f[4]) > 1024'
|
|
56
|
+
|
|
57
|
+
Matching a single field (any filename with "t" in it):
|
|
58
|
+
|
|
59
|
+
ls -l | awk '$NF ~/t/'
|
|
60
|
+
ls -l | pawk '"t" in f[-1]'
|
|
61
|
+
|
|
62
|
+
## Expression evaluation
|
|
63
|
+
|
|
64
|
+
PAWK evaluates a Python expression or statement against each line in stdin. The following variables are available in
|
|
65
|
+
local context:
|
|
66
|
+
|
|
67
|
+
- `line` - Current line text, including newline.
|
|
68
|
+
- `l` - Current line text, excluding newline.
|
|
69
|
+
- `n` - The current 1-based line number.
|
|
70
|
+
- `f` - Fields of the line (split by the field separator `-F`).
|
|
71
|
+
- `nf` - Number of fields in this line.
|
|
72
|
+
- `m` - Tuple of match regular expression capture groups, if any.
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
In the context of the `-E` block:
|
|
76
|
+
|
|
77
|
+
- `t` - The entire input text up to the current cursor position.
|
|
78
|
+
|
|
79
|
+
If the flag `-H, --header` is provided, each field in the first row of the input will be treated as field variable names
|
|
80
|
+
in subsequent rows. The header is not output. For example, given the input:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
count name
|
|
84
|
+
12 bob
|
|
85
|
+
34 fred
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
We could do:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
$ pawk -H '"%s is %s" % (name, count)' < input.txt
|
|
92
|
+
bob is 12
|
|
93
|
+
fred is 34
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
To output a header as well, use `-B`:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
$ pawk -H -B '"name is count"' '"%s is %s" % (name, count)' < input.txt
|
|
100
|
+
name is count
|
|
101
|
+
bob is 12
|
|
102
|
+
fred is 34
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Module references will be automatically imported if possible. Additionally, the `--import <module>[,<module>,...]` flag
|
|
106
|
+
can be used to import symbols from a set of modules into the evaluation context.
|
|
107
|
+
|
|
108
|
+
eg. `--import os.path` will import all symbols from `os.path`, such as `os.path.isfile()`, into the context.
|
|
109
|
+
|
|
110
|
+
## Output
|
|
111
|
+
|
|
112
|
+
### Line actions
|
|
113
|
+
|
|
114
|
+
The type of the evaluated expression determines how output is displayed:
|
|
115
|
+
|
|
116
|
+
- `tuple` or `list`: the elements are converted to strings and joined with the output delimiter (`-O`).
|
|
117
|
+
- `None` or `False`: nothing is output for that line.
|
|
118
|
+
- `True`: the original line is output.
|
|
119
|
+
- Any other value is converted to a string.
|
|
120
|
+
|
|
121
|
+
### Start/end blocks
|
|
122
|
+
|
|
123
|
+
The rules are the same as for line actions with one difference. Because there is no "line" that corresponds to them, an
|
|
124
|
+
expression returning True is ignored.
|
|
125
|
+
|
|
126
|
+
$ echo -ne 'foo\nbar' | pawk -E t
|
|
127
|
+
foo
|
|
128
|
+
bar
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
## Command-line usage
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
Usage: cat input | pawk [<options>] <expr>
|
|
135
|
+
|
|
136
|
+
A Python line-processor (like awk).
|
|
137
|
+
|
|
138
|
+
See https://github.com/alecthomas/pawk for details. Based on
|
|
139
|
+
http://code.activestate.com/recipes/437932/.
|
|
140
|
+
|
|
141
|
+
Options:
|
|
142
|
+
-h, --help show this help message and exit
|
|
143
|
+
-I <filename>, --in_place=<filename>
|
|
144
|
+
modify given input file in-place
|
|
145
|
+
-i <modules>, --import=<modules>
|
|
146
|
+
comma-separated list of modules to "from x import *"
|
|
147
|
+
from
|
|
148
|
+
-F <delim> input delimiter
|
|
149
|
+
-O <delim> output delimiter
|
|
150
|
+
-L <delim> output line separator
|
|
151
|
+
-B <statement>, --begin=<statement>
|
|
152
|
+
begin statement
|
|
153
|
+
-E <statement>, --end=<statement>
|
|
154
|
+
end statement
|
|
155
|
+
-s, --statement DEPRECATED. retained for backward compatibility
|
|
156
|
+
-H, --header use first row as field variable names in subsequent
|
|
157
|
+
rows
|
|
158
|
+
--strict abort on exceptions
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Examples
|
|
162
|
+
|
|
163
|
+
### Line processing
|
|
164
|
+
|
|
165
|
+
Print the name and size of every file from stdin:
|
|
166
|
+
|
|
167
|
+
find . -type f | pawk 'f[0], os.stat(f[0]).st_size'
|
|
168
|
+
|
|
169
|
+
> **Note:** this example also shows how pawk automatically imports referenced modules, in this case `os`.
|
|
170
|
+
|
|
171
|
+
Print the sum size of all files from stdin:
|
|
172
|
+
|
|
173
|
+
find . -type f | \
|
|
174
|
+
pawk \
|
|
175
|
+
--begin 'c=0' \
|
|
176
|
+
--end c \
|
|
177
|
+
'c += os.stat(f[0]).st_size'
|
|
178
|
+
|
|
179
|
+
Short-flag version:
|
|
180
|
+
|
|
181
|
+
find . -type f | pawk -B c=0 -E c 'c += os.stat(f[0]).st_size'
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
### Whole-file processing
|
|
185
|
+
|
|
186
|
+
If you do not provide a line expression, but do provide an end statement, pawk will accumulate each line, and the entire
|
|
187
|
+
file's text will be available in the end statement as `t`. This is useful for operations on entire files, like the
|
|
188
|
+
following example of converting a file from markdown to HTML:
|
|
189
|
+
|
|
190
|
+
cat README.md | \
|
|
191
|
+
pawk --end 'markdown.markdown(t)'
|
|
192
|
+
|
|
193
|
+
Short-flag version:
|
|
194
|
+
|
|
195
|
+
cat README.md | pawk -E 'markdown.markdown(t)'
|
omdev/tui/apps/edit/main.py
CHANGED
|
@@ -19,13 +19,17 @@ class QuitConfirmScreen(tx.ModalScreen[bool]):
|
|
|
19
19
|
#dialog {
|
|
20
20
|
width: 60;
|
|
21
21
|
height: 11;
|
|
22
|
+
|
|
22
23
|
border: thick $background 80%;
|
|
23
|
-
|
|
24
|
+
|
|
24
25
|
padding: 1 2;
|
|
26
|
+
|
|
27
|
+
background: $surface;
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
#question {
|
|
28
31
|
height: 3;
|
|
32
|
+
|
|
29
33
|
content-align: center middle;
|
|
30
34
|
}
|
|
31
35
|
|
omdev/tui/apps/irc/app.py
CHANGED
|
@@ -43,26 +43,34 @@ class IrcApp(tx.App):
|
|
|
43
43
|
_commands: ta.ClassVar[ta.Mapping[str, IrcCommand]] = ALL_COMMANDS
|
|
44
44
|
|
|
45
45
|
CSS = """
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
46
|
+
#messages {
|
|
47
|
+
height: 1fr;
|
|
48
|
+
|
|
49
|
+
border: none;
|
|
50
|
+
|
|
51
|
+
padding: 0;
|
|
52
|
+
|
|
53
|
+
overflow-y: auto;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
#status {
|
|
57
|
+
height: 1;
|
|
58
|
+
|
|
59
|
+
border: none;
|
|
60
|
+
|
|
61
|
+
padding: 0;
|
|
62
|
+
|
|
63
|
+
color: $text;
|
|
64
|
+
background: $primary;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
#input {
|
|
68
|
+
border: none;
|
|
69
|
+
|
|
70
|
+
padding: 0;
|
|
71
|
+
|
|
72
|
+
dock: bottom;
|
|
73
|
+
}
|
|
66
74
|
"""
|
|
67
75
|
|
|
68
76
|
BINDINGS: ta.ClassVar[ta.Sequence[tx.Binding]] = [
|
omdev/tui/apps/irc/commands.py
CHANGED
omdev/tui/rich/__init__.py
CHANGED
|
@@ -6,15 +6,27 @@ from omlish import lang as _lang
|
|
|
6
6
|
with _lang.auto_proxy_init(globals()):
|
|
7
7
|
##
|
|
8
8
|
|
|
9
|
+
from rich import align # noqa
|
|
9
10
|
from rich import console # noqa
|
|
10
11
|
from rich import live # noqa
|
|
11
12
|
from rich import markdown # noqa
|
|
12
13
|
from rich import repr # noqa
|
|
13
14
|
from rich import text # noqa
|
|
15
|
+
from rich.align import Align # noqa
|
|
16
|
+
from rich.color import Color # noqa
|
|
17
|
+
from rich.color import blend_rgb # noqa
|
|
18
|
+
from rich.color_triplet import ColorTriplet # noqa
|
|
14
19
|
from rich.console import Console # noqa
|
|
20
|
+
from rich.console import Group # noqa
|
|
15
21
|
from rich.live import Live # noqa
|
|
16
22
|
from rich.markdown import Markdown # noqa
|
|
23
|
+
from rich.segment import Segment # noqa
|
|
24
|
+
from rich.segment import SegmentLines # noqa
|
|
25
|
+
from rich.style import Style # noqa
|
|
26
|
+
from rich.syntax import Syntax # noqa
|
|
27
|
+
from rich.table import Table # noqa
|
|
17
28
|
from rich.text import Text # noqa
|
|
29
|
+
from rich.theme import Theme # noqa
|
|
18
30
|
|
|
19
31
|
##
|
|
20
32
|
|
omdev/tui/textual/__init__.py
CHANGED
|
@@ -6,6 +6,8 @@ from omlish import lang as _lang
|
|
|
6
6
|
with _lang.auto_proxy_init(globals()):
|
|
7
7
|
##
|
|
8
8
|
|
|
9
|
+
from textual import LogGroup # noqa
|
|
10
|
+
from textual import LogVerbosity # noqa
|
|
9
11
|
from textual import app # noqa
|
|
10
12
|
from textual import binding # noqa
|
|
11
13
|
from textual import constants # noqa
|
|
@@ -78,6 +80,8 @@ with _lang.auto_proxy_init(globals()):
|
|
|
78
80
|
from textual.content import ContentType # noqa
|
|
79
81
|
from textual.content import EMPTY_CONTENT # noqa
|
|
80
82
|
from textual.content import Span # noqa
|
|
83
|
+
from textual.dom import DOMError # noqa
|
|
84
|
+
from textual.dom import DOMNode # noqa
|
|
81
85
|
from textual.driver import Driver # noqa
|
|
82
86
|
from textual.events import Action # noqa
|
|
83
87
|
from textual.events import AppBlur # noqa
|
|
@@ -210,12 +214,38 @@ with _lang.auto_proxy_init(globals()):
|
|
|
210
214
|
from textual.widgets import Tooltip # noqa
|
|
211
215
|
from textual.widgets import Tree # noqa
|
|
212
216
|
from textual.widgets import Welcome # noqa
|
|
213
|
-
from textual.widgets.
|
|
214
|
-
from textual.widgets.
|
|
217
|
+
from textual.widgets.markdown import MarkdownBlock # noqa
|
|
218
|
+
from textual.widgets.markdown import MarkdownFence # noqa
|
|
219
|
+
from textual.widgets.markdown import MarkdownStream # noqa
|
|
220
|
+
from textual.widgets.markdown import MarkdownTableOfContents # noqa
|
|
215
221
|
from textual.widgets.option_list import DuplicateID # noqa
|
|
222
|
+
from textual.widgets.option_list import Option # noqa
|
|
223
|
+
from textual.widgets.option_list import OptionDoesNotExist # noqa
|
|
216
224
|
|
|
217
225
|
##
|
|
218
226
|
|
|
227
|
+
from textual_dev.client import DevtoolsClient # noqa
|
|
228
|
+
from textual_dev.client import DevtoolsConnectionError # noqa
|
|
229
|
+
from textual_dev.client import DevtoolsConsole # noqa
|
|
230
|
+
from textual_dev.client import DevtoolsLog # noqa
|
|
231
|
+
|
|
232
|
+
##
|
|
233
|
+
|
|
234
|
+
from . devtools import ( # noqa
|
|
235
|
+
DevtoolsConfig,
|
|
236
|
+
connect_devtools,
|
|
237
|
+
|
|
238
|
+
DevtoolsAppMixin,
|
|
239
|
+
|
|
240
|
+
DevtoolsSetup,
|
|
241
|
+
DevtoolsManager,
|
|
242
|
+
|
|
243
|
+
DevtoolsLoggingHandler,
|
|
244
|
+
set_root_logger_to_devtools,
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
from . import debug # noqa
|
|
248
|
+
|
|
219
249
|
from .app2 import ( # noqa
|
|
220
250
|
App,
|
|
221
251
|
)
|
|
@@ -224,3 +254,12 @@ with _lang.auto_proxy_init(globals()):
|
|
|
224
254
|
PendingWritesDriverMixin,
|
|
225
255
|
get_pending_writes_driver_class,
|
|
226
256
|
)
|
|
257
|
+
|
|
258
|
+
from .logging2 import ( # noqa
|
|
259
|
+
translate_log_level,
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
from .types import ( # noqa
|
|
263
|
+
TopRightBottomLeft,
|
|
264
|
+
trbl_to_dict,
|
|
265
|
+
)
|
omdev/tui/textual/app2.py
CHANGED
|
@@ -3,9 +3,14 @@ import typing as ta
|
|
|
3
3
|
from textual.app import App as App_
|
|
4
4
|
from textual.binding import BindingType # noqa
|
|
5
5
|
|
|
6
|
+
from .devtools import DevtoolsAppMixin
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
##
|
|
8
10
|
|
|
9
11
|
|
|
10
|
-
class App(
|
|
12
|
+
class App(
|
|
13
|
+
DevtoolsAppMixin,
|
|
14
|
+
App_,
|
|
15
|
+
):
|
|
11
16
|
BINDINGS: ta.ClassVar[ta.Sequence[BindingType]] = App_.BINDINGS # type: ignore[assignment]
|