omdev 0.0.0.dev114__tar.gz → 0.0.0.dev116__tar.gz

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.

Files changed (159) hide show
  1. {omdev-0.0.0.dev114/omdev.egg-info → omdev-0.0.0.dev116}/PKG-INFO +2 -2
  2. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/.manifests.json +2 -2
  3. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cli/clicli.py +2 -0
  4. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cli/main.py +0 -1
  5. omdev-0.0.0.dev116/omdev/clipboard/clipboard.py +74 -0
  6. omdev-0.0.0.dev114/omdev/clipboard/darwin.py → omdev-0.0.0.dev116/omdev/clipboard/darwin_cf.py +31 -27
  7. omdev-0.0.0.dev116/omdev/clipboard/linux_x.py +301 -0
  8. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/git.py +27 -27
  9. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/pip.py +1 -1
  10. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/pycharm/cli.py +12 -10
  11. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/pyproject/cli.py +20 -14
  12. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/scripts/pyproject.py +47 -41
  13. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/tools/git.py +32 -18
  14. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116/omdev.egg-info}/PKG-INFO +2 -2
  15. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev.egg-info/SOURCES.txt +2 -2
  16. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev.egg-info/requires.txt +1 -1
  17. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/pyproject.toml +2 -2
  18. omdev-0.0.0.dev114/omdev/clipboard/clipboard.py +0 -23
  19. omdev-0.0.0.dev114/omdev/tools/pawk/__init__.py +0 -0
  20. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/LICENSE +0 -0
  21. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/MANIFEST.in +0 -0
  22. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/README.rst +0 -0
  23. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/__about__.py +0 -0
  24. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/__init__.py +0 -0
  25. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/amalg/__init__.py +0 -0
  26. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/amalg/__main__.py +0 -0
  27. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/amalg/amalg.py +0 -0
  28. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/antlr/__init__.py +0 -0
  29. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/antlr/consts.py +0 -0
  30. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/antlr/gen.py +0 -0
  31. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/bracepy.py +0 -0
  32. {omdev-0.0.0.dev114/omdev/antlr/_antlr → omdev-0.0.0.dev116/omdev/cache}/__init__.py +0 -0
  33. {omdev-0.0.0.dev114/omdev/cache → omdev-0.0.0.dev116/omdev/cache/compute}/__init__.py +0 -0
  34. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cache/compute/cache.py +0 -0
  35. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cache/compute/contexts.py +0 -0
  36. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cache/compute/currents.py +0 -0
  37. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cache/compute/fns.py +0 -0
  38. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cache/compute/resolvers.py +0 -0
  39. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cache/compute/storage.py +0 -0
  40. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cache/compute/types.py +0 -0
  41. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cache/data/__init__.py +0 -0
  42. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cache/data/actions.py +0 -0
  43. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cache/data/cache.py +0 -0
  44. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cache/data/consts.py +0 -0
  45. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cache/data/defaults.py +0 -0
  46. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cache/data/manifests.py +0 -0
  47. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cache/data/specs.py +0 -0
  48. {omdev-0.0.0.dev114/omdev/cache/compute → omdev-0.0.0.dev116/omdev/cexts}/__init__.py +0 -0
  49. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_boilerplate.cc +0 -0
  50. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_distutils/LICENSE +0 -0
  51. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_distutils/__init__.py +0 -0
  52. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_distutils/build_ext.py +0 -0
  53. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_distutils/compilers/__init__.py +0 -0
  54. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_distutils/compilers/ccompiler.py +0 -0
  55. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_distutils/compilers/options.py +0 -0
  56. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_distutils/compilers/unixccompiler.py +0 -0
  57. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_distutils/dir_util.py +0 -0
  58. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_distutils/errors.py +0 -0
  59. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_distutils/extension.py +0 -0
  60. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_distutils/file_util.py +0 -0
  61. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_distutils/modified.py +0 -0
  62. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_distutils/spawn.py +0 -0
  63. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_distutils/sysconfig.py +0 -0
  64. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_distutils/util.py +0 -0
  65. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/_distutils/version.py +0 -0
  66. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/build.py +0 -0
  67. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/cmake.py +0 -0
  68. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/importhook.py +0 -0
  69. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/magic.py +0 -0
  70. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cexts/scan.py +0 -0
  71. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/classdot.py +0 -0
  72. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cli/__init__.py +0 -0
  73. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cli/__main__.py +0 -0
  74. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cli/_pathhack.py +0 -0
  75. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cli/install.py +0 -0
  76. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cli/managers.py +0 -0
  77. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cli/types.py +0 -0
  78. {omdev-0.0.0.dev114/omdev/cexts → omdev-0.0.0.dev116/omdev/clipboard}/__init__.py +0 -0
  79. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/cmake.py +0 -0
  80. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/findimports.py +0 -0
  81. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/imgur.py +0 -0
  82. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/interp/__init__.py +0 -0
  83. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/interp/__main__.py +0 -0
  84. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/interp/cli.py +0 -0
  85. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/interp/inspect.py +0 -0
  86. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/interp/providers.py +0 -0
  87. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/interp/pyenv.py +0 -0
  88. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/interp/resolvers.py +0 -0
  89. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/interp/standalone.py +0 -0
  90. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/interp/system.py +0 -0
  91. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/interp/types.py +0 -0
  92. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/magic/__init__.py +0 -0
  93. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/magic/find.py +0 -0
  94. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/magic/magic.py +0 -0
  95. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/magic/prepare.py +0 -0
  96. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/magic/styles.py +0 -0
  97. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/manifests/__init__.py +0 -0
  98. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/manifests/build.py +0 -0
  99. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/manifests/load.py +0 -0
  100. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/manifests/types.py +0 -0
  101. {omdev-0.0.0.dev114/omdev/clipboard → omdev-0.0.0.dev116/omdev/mypy}/__init__.py +0 -0
  102. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/mypy/debug.py +0 -0
  103. {omdev-0.0.0.dev114/omdev/mypy → omdev-0.0.0.dev116/omdev/packaging}/__init__.py +0 -0
  104. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/packaging/marshal.py +0 -0
  105. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/packaging/names.py +0 -0
  106. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/packaging/requires.py +0 -0
  107. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/packaging/specifiers.py +0 -0
  108. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/packaging/versions.py +0 -0
  109. {omdev-0.0.0.dev114/omdev/packaging → omdev-0.0.0.dev116/omdev/precheck}/__init__.py +0 -0
  110. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/precheck/__main__.py +0 -0
  111. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/precheck/base.py +0 -0
  112. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/precheck/git.py +0 -0
  113. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/precheck/lite.py +0 -0
  114. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/precheck/main.py +0 -0
  115. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/precheck/manifests.py +0 -0
  116. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/precheck/scripts.py +0 -0
  117. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/ptk/__init__.py +0 -0
  118. {omdev-0.0.0.dev114/omdev/precheck → omdev-0.0.0.dev116/omdev/ptk/apps}/__init__.py +0 -0
  119. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/ptk/apps/ncdu.py +0 -0
  120. {omdev-0.0.0.dev114/omdev/ptk/apps → omdev-0.0.0.dev116/omdev/pycharm}/__init__.py +0 -0
  121. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/pycharm/__main__.py +0 -0
  122. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/pyproject/__init__.py +0 -0
  123. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/pyproject/__main__.py +0 -0
  124. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/pyproject/cexts.py +0 -0
  125. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/pyproject/configs.py +0 -0
  126. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/pyproject/pkg.py +0 -0
  127. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/pyproject/reqs.py +0 -0
  128. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/revisions.py +0 -0
  129. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/scripts/__init__.py +0 -0
  130. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/scripts/bumpversion.py +0 -0
  131. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/scripts/execrss.py +0 -0
  132. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/scripts/exectime.py +0 -0
  133. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/scripts/importtrace.py +0 -0
  134. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/scripts/interp.py +0 -0
  135. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/scripts/slowcat.py +0 -0
  136. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/scripts/tmpexec.py +0 -0
  137. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/secrets.py +0 -0
  138. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/tokens.py +0 -0
  139. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/toml/__init__.py +0 -0
  140. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/toml/parser.py +0 -0
  141. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/toml/writer.py +0 -0
  142. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/tools/__init__.py +0 -0
  143. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/tools/doc.py +0 -0
  144. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/tools/docker.py +0 -0
  145. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/tools/importscan.py +0 -0
  146. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/tools/mkrelimp.py +0 -0
  147. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/tools/notebook.py +0 -0
  148. {omdev-0.0.0.dev114/omdev/pycharm → omdev-0.0.0.dev116/omdev/tools/pawk}/__init__.py +0 -0
  149. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/tools/pawk/__main__.py +0 -0
  150. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/tools/pawk/pawk.py +0 -0
  151. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/tools/pip.py +0 -0
  152. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/tools/prof.py +0 -0
  153. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/tools/qr.py +0 -0
  154. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/tools/sqlrepl.py +0 -0
  155. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev/wheelfile.py +0 -0
  156. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev.egg-info/dependency_links.txt +0 -0
  157. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev.egg-info/entry_points.txt +0 -0
  158. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/omdev.egg-info/top_level.txt +0 -0
  159. {omdev-0.0.0.dev114 → omdev-0.0.0.dev116}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omdev
3
- Version: 0.0.0.dev114
3
+ Version: 0.0.0.dev116
4
4
  Summary: omdev
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -12,7 +12,7 @@ Classifier: Operating System :: OS Independent
12
12
  Classifier: Operating System :: POSIX
13
13
  Requires-Python: >=3.12
14
14
  License-File: LICENSE
15
- Requires-Dist: omlish==0.0.0.dev114
15
+ Requires-Dist: omlish==0.0.0.dev116
16
16
  Provides-Extra: all
17
17
  Requires-Dist: black~=24.10; extra == "all"
18
18
  Requires-Dist: pycparser~=2.22; extra == "all"
@@ -51,7 +51,7 @@
51
51
  "module": ".cli.clicli",
52
52
  "attr": "_CLI_MODULE",
53
53
  "file": "omdev/cli/clicli.py",
54
- "line": 111,
54
+ "line": 113,
55
55
  "value": {
56
56
  "$.cli.types.CliModule": {
57
57
  "cmd_name": "cli",
@@ -243,7 +243,7 @@
243
243
  "module": ".tools.git",
244
244
  "attr": "_CLI_MODULE",
245
245
  "file": "omdev/tools/git.py",
246
- "line": 182,
246
+ "line": 196,
247
247
  "value": {
248
248
  "$.cli.types.CliModule": {
249
249
  "cmd_name": "git",
@@ -89,6 +89,8 @@ class CliCli(ap.Cli):
89
89
  print('Continue with reinstall? (ctrl-c to cancel)')
90
90
  input()
91
91
 
92
+ #
93
+
92
94
  if self.args.local:
93
95
  install_src = inspect.getsource(install)
94
96
  else:
@@ -1,6 +1,5 @@
1
1
  """
2
2
  TODO:
3
- - py/foo - root command 'py'
4
3
  - cache ldr.discover() somehow if in uvx/pipx - very slow
5
4
  - <venv-root>/.omdev-cli-manifest-cache.json - {pkg_name: manifests_json}
6
5
  - allow manually specifying manifest packages
@@ -0,0 +1,74 @@
1
+ """ https://askubuntu.com/questions/11925/a-command-line-clipboard-copy-and-paste-utility
2
+ """
3
+ import abc
4
+ import dataclasses as dc
5
+ import subprocess
6
+ import typing as ta
7
+
8
+ from omlish import lang
9
+
10
+
11
+ ##
12
+
13
+
14
+ @dc.dataclass(frozen=True)
15
+ class ClipboardContents(lang.Abstract):
16
+ pass
17
+
18
+
19
+ @dc.dataclass(frozen=True)
20
+ class TextClipboardContents(ClipboardContents):
21
+ s: str
22
+
23
+
24
+ @dc.dataclass(frozen=True)
25
+ class ImageClipboardContents(ClipboardContents):
26
+ b: bytes
27
+
28
+
29
+ ##
30
+
31
+
32
+ class Clipboard(abc.ABC):
33
+ @abc.abstractmethod
34
+ def get(self) -> list[ClipboardContents]:
35
+ raise NotImplementedError
36
+
37
+ @abc.abstractmethod
38
+ def put(self, c: ClipboardContents) -> None:
39
+ raise NotImplementedError
40
+
41
+
42
+ ##
43
+
44
+
45
+ class TextCommandClipboard(Clipboard, lang.Abstract):
46
+ @property
47
+ @abc.abstractmethod
48
+ def _get_cmd(self) -> ta.Sequence[str]:
49
+ raise NotImplementedError
50
+
51
+ def get(self) -> list[ClipboardContents]:
52
+ s = subprocess.check_output(self._get_cmd).decode()
53
+ return [TextClipboardContents(s)]
54
+
55
+ @property
56
+ @abc.abstractmethod
57
+ def _put_cmd(self) -> ta.Sequence[str]:
58
+ raise NotImplementedError
59
+
60
+ def put(self, c: ClipboardContents) -> None:
61
+ if isinstance(c, TextClipboardContents):
62
+ subprocess.run(self._put_cmd, input=c.s.encode(), check=True)
63
+ else:
64
+ raise TypeError(c)
65
+
66
+
67
+ class XclipLinuxClipboard(TextCommandClipboard):
68
+ _get_cmd = ('xclip', '-selection', 'clipboard', '-o')
69
+ _put_cmd = ('xclip', '-selection', 'clipboard')
70
+
71
+
72
+ class PbcopyDarwinClipboard(TextCommandClipboard):
73
+ _get_cmd = ('pbpaste',)
74
+ _put_cmd = ('pbcopy',)
@@ -1,31 +1,4 @@
1
1
  # ruff: noqa: N802 N816
2
- """
3
- imageProperties = dict(
4
- ColorModel = "RGB"
5
- DPIHeight = 144
6
- DPIWidth = 144
7
- Depth = 8
8
- PixelHeight = 1236
9
- PixelWidth = 602
10
- ProfileName = "Color LCD"
11
- kCGImageDestinationAllowAlpha = true
12
- {Exif} = dict(
13
- PixelXDimension = 602
14
- PixelYDimension = 1236
15
- UserComment = "Screenshot"
16
- )
17
- {PNG} = dict(
18
- InterlaceType = 0
19
- XPixelsPerMeter = 5669
20
- YPixelsPerMeter = 5669
21
- )
22
- {TIFF} = dict(
23
- ResolutionUnit = 2
24
- XResolution = 144
25
- YResolution = 144
26
- )
27
- )
28
- """
29
2
  import ctypes as ct
30
3
  import ctypes.util
31
4
  import dataclasses as dc
@@ -34,6 +7,11 @@ import typing as ta
34
7
 
35
8
  from omlish import check
36
9
 
10
+ from .clipboard import Clipboard
11
+ from .clipboard import ClipboardContents
12
+ from .clipboard import ImageClipboardContents
13
+ from .clipboard import TextClipboardContents
14
+
37
15
 
38
16
  ##
39
17
 
@@ -254,6 +232,32 @@ def get_darwin_clipboard_data(
254
232
  ##
255
233
 
256
234
 
235
+ _TEXT_TYPE = 'public.utf8-plain-text'
236
+ _IMAGE_TYPE = 'public.png'
237
+
238
+
239
+ class CfDarwinClipboard(Clipboard):
240
+
241
+ def get(self) -> list[ClipboardContents]:
242
+ ret: list[ClipboardContents] = []
243
+ for i in get_darwin_clipboard_data(types={_TEXT_TYPE, _IMAGE_TYPE}):
244
+ if i.type == _TEXT_TYPE:
245
+ if i.data is not None:
246
+ ret.append(TextClipboardContents(i.data.decode('utf-8')))
247
+ elif i.type == _IMAGE_TYPE:
248
+ if i.data is not None:
249
+ ret.append(ImageClipboardContents(i.data))
250
+ else:
251
+ raise KeyError(i.type)
252
+ return ret
253
+
254
+ def put(self, c: ClipboardContents) -> None:
255
+ raise TypeError(self)
256
+
257
+
258
+ ##
259
+
260
+
257
261
  def _main() -> None:
258
262
  for i in get_darwin_clipboard_data(skip_types={'public.heics'}):
259
263
  print(f'type: {i.type}, len: {len(i.data) if i.data is not None else None}')
@@ -0,0 +1,301 @@
1
+ # ruff: noqa: RUF012
2
+ # flake8: noqa: E302 E305
3
+ import ctypes as ct
4
+ import ctypes.util
5
+ import sys
6
+
7
+
8
+ ##
9
+
10
+
11
+ if getattr(sys, 'platform') != 'linux':
12
+ raise OSError(sys.platform)
13
+
14
+
15
+ ##
16
+ # x11
17
+
18
+ x11 = ct.CDLL(ct.util.find_library('X11'))
19
+
20
+ #
21
+
22
+ Atom = ct.c_ulong
23
+ Bool = ct.c_int
24
+ Display = ct.c_void_p
25
+ Status = ct.c_int
26
+ Time = ct.c_ulong
27
+ Window = ct.c_ulong
28
+
29
+ #
30
+
31
+ class XEvent(ct.Structure):
32
+ _fields_ = [
33
+ ('type', ct.c_int),
34
+ ('xselection', ct.c_ulong * 24), # noqa
35
+ ]
36
+
37
+ #
38
+
39
+ x11.XCloseDisplay.argtypes = [Display]
40
+ x11.XCloseDisplay.restype = None
41
+
42
+ x11.XConvertSelection.argtypes = [Display, Atom, Atom, Atom, Window, Time]
43
+ x11.XConvertSelection.restype = None
44
+
45
+ x11.XCreateSimpleWindow.argtypes = [
46
+ Display,
47
+ Window,
48
+ ct.c_int,
49
+ ct.c_int,
50
+ ct.c_uint,
51
+ ct.c_uint,
52
+ ct.c_uint,
53
+ ct.c_ulong,
54
+ ct.c_ulong,
55
+ ]
56
+ x11.XCreateSimpleWindow.restype = Window
57
+
58
+ x11.XDefaultScreen.argtypes = [Display]
59
+ x11.XDefaultScreen.restype = ct.c_int
60
+
61
+ x11.XDestroyWindow.argtypes = [Display, Window]
62
+ x11.XDestroyWindow.restype = None
63
+
64
+ x11.XFlush.argtypes = [Display]
65
+ x11.XFlush.restype = None
66
+
67
+ x11.XFree.argtypes = [ct.c_void_p]
68
+ x11.XFree.restype = None
69
+
70
+ x11.XGetWindowProperty.argtypes = [
71
+ Display,
72
+ Window,
73
+ Atom,
74
+ ct.c_long,
75
+ ct.c_long,
76
+ Bool,
77
+ Atom,
78
+ ct.POINTER(Atom),
79
+ ct.POINTER(ct.c_int),
80
+ ct.POINTER(ct.c_ulong),
81
+ ct.POINTER(ct.c_ulong),
82
+ ct.POINTER(ct.c_void_p),
83
+ ]
84
+ x11.XGetWindowProperty.restype = Status
85
+
86
+ x11.XInternAtom.argtypes = [Display, ct.c_char_p, Bool]
87
+ x11.XInternAtom.restype = Atom
88
+
89
+ x11.XNextEvent.argtypes = [Display, ct.POINTER(XEvent)]
90
+ x11.XNextEvent.restype = None
91
+
92
+ x11.XOpenDisplay.argtypes = [ct.c_char_p]
93
+ x11.XOpenDisplay.restype = Display
94
+
95
+ x11.XRootWindow.argtypes = [Display, ct.c_int]
96
+ x11.XRootWindow.restype = Window
97
+
98
+
99
+ ##
100
+
101
+
102
+ def atom_to_string(display, atom) -> str:
103
+ x11.XGetAtomName.argtypes = [Display, Atom]
104
+ x11.XGetAtomName.restype = ct.c_char_p
105
+ return x11.XGetAtomName(display, atom).decode('utf-8')
106
+
107
+
108
+ ##
109
+
110
+
111
+ def get_clipboard_text(display, window):
112
+ clipboard = x11.XInternAtom(display, b'CLIPBOARD', False)
113
+ utf8_string = x11.XInternAtom(display, b'UTF8_STRING', False)
114
+ target_property = x11.XInternAtom(display, b'XSEL_DATA', False)
115
+
116
+ x11.XConvertSelection(
117
+ display,
118
+ clipboard,
119
+ utf8_string,
120
+ target_property,
121
+ window,
122
+ 0,
123
+ )
124
+ x11.XFlush(display)
125
+
126
+ event = XEvent()
127
+ x11.XNextEvent(display, ct.byref(event))
128
+
129
+ if event.type != 31: # SelectionNotify event type
130
+ print('Failed to receive SelectionNotify event')
131
+ return
132
+
133
+ if event.xselection[4] == 0: # None
134
+ print('No clipboard data available')
135
+ return
136
+
137
+ actual_type = Atom()
138
+ actual_format = ct.c_int()
139
+ nitems = ct.c_ulong()
140
+ bytes_after = ct.c_ulong()
141
+ data = ct.c_void_p()
142
+
143
+ status = x11.XGetWindowProperty(
144
+ display,
145
+ window,
146
+ target_property,
147
+ 0,
148
+ ~0,
149
+ False,
150
+ 0,
151
+ ct.byref(actual_type),
152
+ ct.byref(actual_format),
153
+ ct.byref(nitems),
154
+ ct.byref(bytes_after),
155
+ ct.byref(data),
156
+ )
157
+ try:
158
+ if status != 0 or not data:
159
+ print('Failed to get clipboard data')
160
+ return
161
+
162
+ clipboard_text = ct.cast(data, ct.c_char_p).value
163
+ print(f'Clipboard text: {clipboard_text.decode("utf-8") if clipboard_text else ""}')
164
+
165
+ finally:
166
+ x11.XFree(data)
167
+
168
+
169
+ def get_clipboard_image(display, window):
170
+ clipboard = x11.XInternAtom(display, b'CLIPBOARD', False)
171
+ target_property = x11.XInternAtom(display, b'XSEL_DATA', False)
172
+ targets_atom = x11.XInternAtom(display, b'TARGETS', False)
173
+
174
+ x11.XConvertSelection(
175
+ display,
176
+ clipboard,
177
+ targets_atom,
178
+ target_property,
179
+ window,
180
+ 0,
181
+ )
182
+ x11.XFlush(display)
183
+
184
+ event = XEvent()
185
+ x11.XNextEvent(display, ct.byref(event))
186
+
187
+ if event.type != 31 or event.xselection[4] == 0:
188
+ print('Failed to receive SelectionNotify event for image')
189
+ return
190
+
191
+ actual_type = Atom()
192
+ actual_format = ct.c_int()
193
+ nitems = ct.c_ulong()
194
+ bytes_after = ct.c_ulong()
195
+ data = ct.c_void_p()
196
+
197
+ status = x11.XGetWindowProperty(
198
+ display,
199
+ window,
200
+ target_property,
201
+ 0,
202
+ ~0,
203
+ False,
204
+ 4,
205
+ ct.byref(actual_type),
206
+ ct.byref(actual_format),
207
+ ct.byref(nitems),
208
+ ct.byref(bytes_after),
209
+ ct.byref(data),
210
+ )
211
+ try:
212
+ if status != 0 or not data:
213
+ print('Failed to get available targets')
214
+ return
215
+
216
+ png_atom = x11.XInternAtom(display, b'image/png', False)
217
+ atoms = ct.cast(data, ct.POINTER(Atom))
218
+ for i in range(nitems.value):
219
+ if atoms[i] != png_atom:
220
+ continue
221
+
222
+ x11.XConvertSelection(
223
+ display,
224
+ clipboard,
225
+ png_atom,
226
+ target_property,
227
+ window,
228
+ 0,
229
+ )
230
+ x11.XFlush(display)
231
+ x11.XNextEvent(display, ct.byref(event))
232
+
233
+ if event.type != 31 or event.xselection[4] == 0:
234
+ print('Failed to receive SelectionNotify event for PNG image')
235
+ return
236
+
237
+ status = x11.XGetWindowProperty(
238
+ display,
239
+ window,
240
+ target_property,
241
+ 0,
242
+ ~0,
243
+ False,
244
+ 0,
245
+ ct.byref(actual_type),
246
+ ct.byref(actual_format),
247
+ ct.byref(nitems),
248
+ ct.byref(bytes_after),
249
+ ct.byref(data),
250
+ )
251
+
252
+ if status == 0 and data:
253
+ data_bytes = ct.string_at(data.value, nitems.value) # type: ignore
254
+
255
+ print(f'Clipboard image: {len(data_bytes)} bytes')
256
+
257
+ return
258
+
259
+ print('No image data available on clipboard')
260
+
261
+ finally:
262
+ if data:
263
+ x11.XFree(data)
264
+
265
+
266
+ ##
267
+
268
+
269
+ def main() -> None:
270
+ display = x11.XOpenDisplay(None)
271
+ try:
272
+ if not display:
273
+ print('Failed to open X display')
274
+ return
275
+
276
+ screen = x11.XDefaultScreen(display)
277
+ window = x11.XCreateSimpleWindow(
278
+ display,
279
+ x11.XRootWindow(display, screen),
280
+ 0,
281
+ 0,
282
+ 1,
283
+ 1,
284
+ 0,
285
+ 0,
286
+ 0,
287
+ )
288
+ try:
289
+ get_clipboard_text(display, window)
290
+ get_clipboard_image(display, window)
291
+
292
+ finally:
293
+ x11.XDestroyWindow(display, window)
294
+
295
+ finally:
296
+ if display:
297
+ x11.XCloseDisplay(display)
298
+
299
+
300
+ if __name__ == '__main__':
301
+ main()
@@ -228,7 +228,7 @@ untracked file, this is reported as ? as well.
228
228
  """ # noqa
229
229
 
230
230
 
231
- class GitStatusLineState(enum.Enum):
231
+ class GitStatusState(enum.Enum):
232
232
  UNMODIFIED = ' '
233
233
  MODIFIED = 'M'
234
234
  FILE_TYPE_CHANGED = 'T'
@@ -242,16 +242,16 @@ class GitStatusLineState(enum.Enum):
242
242
  SUBMODULE_MODIFIED_CONTENT = 'm'
243
243
 
244
244
 
245
- _EXTRA_UNMERGED_GIT_STATUS_LINE_STATES: ta.FrozenSet[ta.Tuple[GitStatusLineState, GitStatusLineState]] = frozenset([
246
- (GitStatusLineState.ADDED, GitStatusLineState.ADDED),
247
- (GitStatusLineState.DELETED, GitStatusLineState.DELETED),
245
+ _EXTRA_UNMERGED_GIT_STATUS_STATES: ta.FrozenSet[ta.Tuple[GitStatusState, GitStatusState]] = frozenset([
246
+ (GitStatusState.ADDED, GitStatusState.ADDED),
247
+ (GitStatusState.DELETED, GitStatusState.DELETED),
248
248
  ])
249
249
 
250
250
 
251
251
  @dc.dataclass(frozen=True)
252
- class GitStatusLine:
253
- x: GitStatusLineState
254
- y: GitStatusLineState
252
+ class GitStatusItem:
253
+ x: GitStatusState
254
+ y: GitStatusState
255
255
 
256
256
  a: str
257
257
  b: ta.Optional[str]
@@ -259,9 +259,9 @@ class GitStatusLine:
259
259
  @property
260
260
  def is_unmerged(self) -> bool:
261
261
  return (
262
- self.x is GitStatusLineState.UPDATED_BUT_UNMERGED or
263
- self.y is GitStatusLineState.UPDATED_BUT_UNMERGED or
264
- (self.x, self.y) in _EXTRA_UNMERGED_GIT_STATUS_LINE_STATES
262
+ self.x is GitStatusState.UPDATED_BUT_UNMERGED or
263
+ self.y is GitStatusState.UPDATED_BUT_UNMERGED or
264
+ (self.x, self.y) in _EXTRA_UNMERGED_GIT_STATUS_STATES
265
265
  )
266
266
 
267
267
  def __repr__(self) -> str:
@@ -275,7 +275,7 @@ class GitStatusLine:
275
275
  )
276
276
 
277
277
 
278
- def parse_git_status_line(l: str) -> GitStatusLine:
278
+ def parse_git_status_line(l: str) -> GitStatusItem:
279
279
  if len(l) < 3 or l[2] != ' ':
280
280
  raise ValueError(l)
281
281
  x, y = l[0], l[1]
@@ -289,25 +289,25 @@ def parse_git_status_line(l: str) -> GitStatusLine:
289
289
  else:
290
290
  raise ValueError(l)
291
291
 
292
- return GitStatusLine(
293
- GitStatusLineState(x),
294
- GitStatusLineState(y),
292
+ return GitStatusItem(
293
+ GitStatusState(x),
294
+ GitStatusState(y),
295
295
  a,
296
296
  b,
297
297
  )
298
298
 
299
299
 
300
- class GitStatus(ta.Sequence[GitStatusLine]):
301
- def __init__(self, lines: ta.Iterable[GitStatusLine]) -> None:
300
+ class GitStatus(ta.Sequence[GitStatusItem]):
301
+ def __init__(self, lines: ta.Iterable[GitStatusItem]) -> None:
302
302
  super().__init__()
303
303
 
304
304
  self._lst = list(lines)
305
305
 
306
- by_x: ta.Dict[GitStatusLineState, list[GitStatusLine]] = {}
307
- by_y: ta.Dict[GitStatusLineState, list[GitStatusLine]] = {}
306
+ by_x: ta.Dict[GitStatusState, list[GitStatusItem]] = {}
307
+ by_y: ta.Dict[GitStatusState, list[GitStatusItem]] = {}
308
308
 
309
- by_a: ta.Dict[str, GitStatusLine] = {}
310
- by_b: ta.Dict[str, GitStatusLine] = {}
309
+ by_a: ta.Dict[str, GitStatusItem] = {}
310
+ by_b: ta.Dict[str, GitStatusItem] = {}
311
311
 
312
312
  for l in self._lst:
313
313
  by_x.setdefault(l.x, []).append(l)
@@ -332,7 +332,7 @@ class GitStatus(ta.Sequence[GitStatusLine]):
332
332
 
333
333
  #
334
334
 
335
- def __iter__(self) -> ta.Iterator[GitStatusLine]:
335
+ def __iter__(self) -> ta.Iterator[GitStatusItem]:
336
336
  return iter(self._lst)
337
337
 
338
338
  def __getitem__(self, index):
@@ -344,19 +344,19 @@ class GitStatus(ta.Sequence[GitStatusLine]):
344
344
  #
345
345
 
346
346
  @property
347
- def by_x(self) -> ta.Mapping[GitStatusLineState, ta.Sequence[GitStatusLine]]:
347
+ def by_x(self) -> ta.Mapping[GitStatusState, ta.Sequence[GitStatusItem]]:
348
348
  return self._by_x
349
349
 
350
350
  @property
351
- def by_y(self) -> ta.Mapping[GitStatusLineState, ta.Sequence[GitStatusLine]]:
351
+ def by_y(self) -> ta.Mapping[GitStatusState, ta.Sequence[GitStatusItem]]:
352
352
  return self._by_y
353
353
 
354
354
  @property
355
- def by_a(self) -> ta.Mapping[str, GitStatusLine]:
355
+ def by_a(self) -> ta.Mapping[str, GitStatusItem]:
356
356
  return self._by_a
357
357
 
358
358
  @property
359
- def by_b(self) -> ta.Mapping[str, GitStatusLine]:
359
+ def by_b(self) -> ta.Mapping[str, GitStatusItem]:
360
360
  return self._by_b
361
361
 
362
362
  #
@@ -367,11 +367,11 @@ class GitStatus(ta.Sequence[GitStatusLine]):
367
367
 
368
368
  @property
369
369
  def has_staged(self) -> bool:
370
- return any(l.x != GitStatusLineState.UNMODIFIED for l in self._lst)
370
+ return any(l.x != GitStatusState.UNMODIFIED for l in self._lst)
371
371
 
372
372
  @property
373
373
  def has_dirty(self) -> bool:
374
- return any(l.y != GitStatusLineState.UNMODIFIED for l in self._lst)
374
+ return any(l.y != GitStatusState.UNMODIFIED for l in self._lst)
375
375
 
376
376
 
377
377
  def parse_git_status(s: str) -> GitStatus:
@@ -30,7 +30,7 @@ def lookup_latest_package_version(
30
30
  pypi_url: str = DEFAULT_PYPI_URL,
31
31
  ) -> str:
32
32
  pkg_name = check.non_empty_str(package)
33
- with urllib.request.urlopen(f'{pypi_url}rss/project/{pkg_name}/releases.xml') as resp: # noqa
33
+ with urllib.request.urlopen(f'{pypi_url.rstrip("/")}/rss/project/{pkg_name}/releases.xml') as resp: # noqa
34
34
  rss = resp.read()
35
35
  doc = ET.parse(io.BytesIO(rss)) # noqa
36
36
  latest = check.not_none(doc.find('./channel/item/title')).text
@@ -1,6 +1,9 @@
1
1
  """
2
2
  TODO:
3
3
  - PyCharm.app/Contents/plugins/python-ce/helpers/pydev/_pydevd_bundle/pydevd_constants.py -> USE_LOW_IMPACT_MONITORING
4
+ - DISPLAY=":1" - ls /tmp/.X11-unix/X1 ?
5
+ - https://unix.stackexchange.com/questions/17255/is-there-a-command-to-list-all-open-displays-on-a-machine
6
+ - w -oush
4
7
  """
5
8
  import inspect
6
9
  import os.path
@@ -22,20 +25,19 @@ return
22
25
 
23
26
 
24
27
  _LINUX_OPEN_SCRIPT = """
25
- # Check if PyCharm is already running
26
- if pgrep -x "pycharm.sh" > /dev/null; then
27
- echo "PyCharm is already running. Opening project..."
28
+ # sudo apt install xdotool wmctrl
28
29
 
29
- # Bring PyCharm to the foreground
30
- wmctrl -a "PyCharm"
30
+ # wmctrl -lx
31
+ # 0x03000054 0 jetbrains-pycharm.jetbrains-pycharm spinlock-ws omlish - cli.py
32
+ # wmctrl -i -a 0x03000054
31
33
 
32
- # Simulate the keyboard shortcut to open a new project
33
- xdotool key --delay 100 ctrl+shift+a
34
- xdotool type "$PROJECT_PATH"
34
+ if pgrep -x "pycharm.sh" > /dev/null; then
35
+ # export DISPLAY=":1"
36
+ wmctrl -x -a jetbrains-pycharm.jetbrains-pycharm
37
+ xdotool key --delay 20 alt+f alt+o
38
+ xdotool type --delay 10 "$(pwd)"
35
39
  xdotool key Return
36
-
37
40
  else
38
- echo "Starting PyCharm with project..."
39
41
  nohup pycharm.sh "$PROJECT_PATH" > /dev/null 2>&1 &
40
42
  fi
41
43
  """