@ossiq/cli-linux-x64 0.1.13 → 0.1.14
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.
- package/bin/ossiq/_internal/_cffi_backend.cpython-313-x86_64-linux-gnu.so +0 -0
- package/bin/ossiq/_internal/base_library.zip +0 -0
- package/bin/ossiq/_internal/cryptography/hazmat/bindings/_rust.abi3.so +0 -0
- package/bin/ossiq/_internal/cryptography-50.0.1.dist-info/METADATA +110 -0
- package/bin/ossiq/_internal/cryptography-50.0.1.dist-info/RECORD +122 -0
- package/bin/ossiq/_internal/cryptography-50.0.1.dist-info/WHEEL +5 -0
- package/bin/ossiq/_internal/cryptography-50.0.1.dist-info/licenses/LICENSE +3 -0
- package/bin/ossiq/_internal/cryptography-50.0.1.dist-info/licenses/LICENSE.APACHE +202 -0
- package/bin/ossiq/_internal/{semantic_version-2.10.0.dist-info/LICENSE → cryptography-50.0.1.dist-info/licenses/LICENSE.BSD} +14 -9
- package/bin/ossiq/_internal/cryptography-50.0.1.dist-info/sboms/cryptography-rust.cyclonedx.json +1365 -0
- package/bin/ossiq/_internal/cryptography-50.0.1.dist-info/sboms/sbom.json +43 -0
- package/bin/ossiq/_internal/keyring-25.7.0.dist-info/METADATA +554 -0
- package/bin/ossiq/_internal/keyring-25.7.0.dist-info/RECORD +40 -0
- package/bin/ossiq/_internal/{semantic_version-2.10.0.dist-info → keyring-25.7.0.dist-info}/WHEEL +1 -2
- package/bin/ossiq/_internal/keyring-25.7.0.dist-info/entry_points.txt +13 -0
- package/bin/ossiq/_internal/keyring-25.7.0.dist-info/licenses/LICENSE +18 -0
- package/bin/ossiq/_internal/keyring-25.7.0.dist-info/top_level.txt +1 -0
- package/bin/ossiq/_internal/lark/grammars/common.lark +59 -0
- package/bin/ossiq/_internal/lark/grammars/lark.lark +62 -0
- package/bin/ossiq/_internal/lark/grammars/python.lark +302 -0
- package/bin/ossiq/_internal/lark/grammars/unicode.lark +7 -0
- package/bin/ossiq/_internal/lark/py.typed +0 -0
- package/bin/ossiq/_internal/libpython3.13.so.1.0 +0 -0
- package/bin/ossiq/_internal/ossiq/data/SKILL.md +42 -16
- package/bin/ossiq/_internal/ossiq/domain/README.md +30 -4
- package/bin/ossiq/_internal/ossiq/solver/README.md +10 -3
- package/bin/ossiq/_internal/ossiq/strategy/README.md +20 -2
- package/bin/ossiq/_internal/ossiq/ui/html_templates/spa_app.html +1828 -1518
- package/bin/ossiq/_internal/ossiq/ui/renderers/export/README.md +103 -40
- package/bin/ossiq/_internal/ossiq/ui/renderers/export/schemas/export_schema_v1.6.json +1805 -0
- package/bin/ossiq/_internal/ossiq/ui/renderers/export/schemas/export_schema_v1.6_standard.json +1328 -0
- package/bin/ossiq/_internal/ossiq-0.1.14.dist-info/INSTALLER +1 -0
- package/bin/ossiq/_internal/ossiq-0.1.14.dist-info/METADATA +207 -0
- package/bin/ossiq/_internal/ossiq-0.1.14.dist-info/RECORD +13 -0
- package/bin/ossiq/_internal/ossiq-0.1.14.dist-info/REQUESTED +0 -0
- package/bin/ossiq/_internal/ossiq-0.1.14.dist-info/uv_cache.json +1 -0
- package/bin/ossiq/_internal/pysolvers.cpython-313-x86_64-linux-gnu.so +0 -0
- package/bin/ossiq/_internal/setuptools/_vendor/importlib_metadata-8.7.1.dist-info/INSTALLER +1 -0
- package/bin/ossiq/_internal/setuptools/_vendor/importlib_metadata-8.7.1.dist-info/METADATA +133 -0
- package/bin/ossiq/_internal/setuptools/_vendor/importlib_metadata-8.7.1.dist-info/RECORD +21 -0
- package/bin/ossiq/_internal/setuptools/_vendor/importlib_metadata-8.7.1.dist-info/REQUESTED +0 -0
- package/bin/ossiq/_internal/setuptools/_vendor/importlib_metadata-8.7.1.dist-info/WHEEL +5 -0
- package/bin/ossiq/_internal/setuptools/_vendor/importlib_metadata-8.7.1.dist-info/licenses/LICENSE +73 -0
- package/bin/ossiq/_internal/setuptools/_vendor/importlib_metadata-8.7.1.dist-info/top_level.txt +1 -0
- package/bin/ossiq/ossiq +0 -0
- package/package.json +1 -1
- package/bin/ossiq/_internal/ossiq-0.1.13.dist-info/METADATA +0 -385
- package/bin/ossiq/_internal/ossiq-0.1.13.dist-info/RECORD +0 -13
- package/bin/ossiq/_internal/ossiq-0.1.13.dist-info/uv_cache.json +0 -1
- package/bin/ossiq/_internal/semantic_version-2.10.0.dist-info/METADATA +0 -324
- package/bin/ossiq/_internal/semantic_version-2.10.0.dist-info/RECORD +0 -10
- package/bin/ossiq/_internal/semantic_version-2.10.0.dist-info/top_level.txt +0 -1
- package/bin/ossiq/_internal/wcwidth/textwrap.py,cover +0 -664
- /package/bin/ossiq/_internal/{ossiq-0.1.13.dist-info → cryptography-50.0.1.dist-info}/INSTALLER +0 -0
- /package/bin/ossiq/_internal/{ossiq-0.1.13.dist-info → cryptography-50.0.1.dist-info}/REQUESTED +0 -0
- /package/bin/ossiq/_internal/{semantic_version-2.10.0.dist-info → keyring-25.7.0.dist-info}/INSTALLER +0 -0
- /package/bin/ossiq/_internal/{semantic_version-2.10.0.dist-info → keyring-25.7.0.dist-info}/REQUESTED +0 -0
- /package/bin/ossiq/_internal/{ossiq-0.1.13.dist-info → ossiq-0.1.14.dist-info}/WHEEL +0 -0
- /package/bin/ossiq/_internal/{ossiq-0.1.13.dist-info → ossiq-0.1.14.dist-info}/direct_url.json +0 -0
- /package/bin/ossiq/_internal/{ossiq-0.1.13.dist-info → ossiq-0.1.14.dist-info}/entry_points.txt +0 -0
- /package/bin/ossiq/_internal/{ossiq-0.1.13.dist-info → ossiq-0.1.14.dist-info}/licenses/AUTHORS +0 -0
- /package/bin/ossiq/_internal/{ossiq-0.1.13.dist-info → ossiq-0.1.14.dist-info}/licenses/LICENSE +0 -0
- /package/bin/ossiq/_internal/{ossiq-0.1.13.dist-info → ossiq-0.1.14.dist-info}/uv_build.json +0 -0
|
@@ -1,664 +0,0 @@
|
|
|
1
|
-
> """
|
|
2
|
-
> Sequence-aware text wrapping functions.
|
|
3
|
-
|
|
4
|
-
> This module provides functions for wrapping text that may contain terminal escape sequences, with
|
|
5
|
-
> proper handling of Unicode grapheme clusters and character display widths.
|
|
6
|
-
> """
|
|
7
|
-
|
|
8
|
-
> from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
# std imports
|
|
11
|
-
> import secrets
|
|
12
|
-
> import textwrap
|
|
13
|
-
|
|
14
|
-
> from typing import TYPE_CHECKING, Optional
|
|
15
|
-
|
|
16
|
-
# local
|
|
17
|
-
> from ._width import width as wcwidth_width
|
|
18
|
-
> from .grapheme import iter_graphemes
|
|
19
|
-
> from .hyperlink import HyperlinkParams
|
|
20
|
-
> from .sgr_state import propagate_sgr as _propagate_sgr
|
|
21
|
-
> from .escape_sequences import ZERO_WIDTH_PATTERN, iter_sequences
|
|
22
|
-
|
|
23
|
-
- if TYPE_CHECKING: # pragma: no cover
|
|
24
|
-
- from typing import Any, Literal
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
> class SequenceTextWrapper(textwrap.TextWrapper):
|
|
28
|
-
> """
|
|
29
|
-
> Sequence-aware text wrapper extending :class:`textwrap.TextWrapper`.
|
|
30
|
-
|
|
31
|
-
> This wrapper properly handles terminal escape sequences and Unicode grapheme clusters when
|
|
32
|
-
> calculating text width for wrapping.
|
|
33
|
-
|
|
34
|
-
> This implementation is based on the SequenceTextWrapper from the 'blessed' library, with
|
|
35
|
-
> contributions from Avram Lubkin and grayjk.
|
|
36
|
-
|
|
37
|
-
> The key difference from the blessed implementation is the addition of grapheme cluster support
|
|
38
|
-
> via :func:`~.iter_graphemes`, providing width calculation for ZWJ emoji sequences, VS-16 emojis
|
|
39
|
-
> and variations, regional indicator flags, and combining characters.
|
|
40
|
-
|
|
41
|
-
> OSC 8 hyperlinks are handled specially: when a hyperlink must span multiple lines, each line
|
|
42
|
-
> receives complete open/close sequences with a shared ``id`` parameter, ensuring terminals
|
|
43
|
-
> treat the fragments as a single hyperlink for hover underlining. If the original hyperlink
|
|
44
|
-
> already has an ``id`` parameter, it is preserved; otherwise, one is generated.
|
|
45
|
-
> """
|
|
46
|
-
|
|
47
|
-
> def __init__(self, width: int = 70, *,
|
|
48
|
-
> control_codes: Literal['parse', 'strict', 'ignore'] = 'parse',
|
|
49
|
-
> tabsize: int = 8,
|
|
50
|
-
> ambiguous_width: int = 1,
|
|
51
|
-
> term_program: bool | str = False,
|
|
52
|
-
> **kwargs: Any) -> None:
|
|
53
|
-
> """
|
|
54
|
-
> Initialize the wrapper.
|
|
55
|
-
|
|
56
|
-
> :param width: Maximum line width in display cells.
|
|
57
|
-
> :param control_codes: How to handle control sequences (see :func:`~.width`).
|
|
58
|
-
> :param tabsize: Tab stop width for tab expansion.
|
|
59
|
-
> :param ambiguous_width: Width to use for East Asian Ambiguous (A) characters.
|
|
60
|
-
> :param term_program: Terminal software identifier for table correction.
|
|
61
|
-
> ``False`` (default) disables override lookup. ``True`` reads the
|
|
62
|
-
> ``TERM_PROGRAM`` or ``TERM`` environment variable for auto-detection.
|
|
63
|
-
> Accepts a canonical terminal name matching :func:`list_term_programs`,
|
|
64
|
-
> such as from XTVERSION_, ENQ_, or ``TERM_PROGRAM``.
|
|
65
|
-
|
|
66
|
-
> .. versionadded:: 0.8.0
|
|
67
|
-
> :param kwargs: Additional arguments passed to :class:`textwrap.TextWrapper`.
|
|
68
|
-
> """
|
|
69
|
-
> super().__init__(width=width, **kwargs)
|
|
70
|
-
> self.control_codes = control_codes
|
|
71
|
-
> self.tabsize = tabsize
|
|
72
|
-
> self.ambiguous_width = ambiguous_width
|
|
73
|
-
> self.term_program = term_program
|
|
74
|
-
|
|
75
|
-
> @staticmethod
|
|
76
|
-
> def _next_hyperlink_id() -> str:
|
|
77
|
-
> """Generate unique hyperlink id as 8-character hex string."""
|
|
78
|
-
> return secrets.token_hex(4)
|
|
79
|
-
|
|
80
|
-
> def _width(self, text: str) -> int:
|
|
81
|
-
> """Measure text width accounting for sequences."""
|
|
82
|
-
> return wcwidth_width(text, control_codes=self.control_codes, tabsize=self.tabsize,
|
|
83
|
-
> ambiguous_width=self.ambiguous_width,
|
|
84
|
-
> term_program=self.term_program)
|
|
85
|
-
|
|
86
|
-
> def _strip_sequences(self, text: str) -> str:
|
|
87
|
-
> """Strip all terminal sequences from text."""
|
|
88
|
-
> result = []
|
|
89
|
-
> for segment, is_seq in iter_sequences(text):
|
|
90
|
-
> if not is_seq:
|
|
91
|
-
> result.append(segment)
|
|
92
|
-
> return ''.join(result)
|
|
93
|
-
|
|
94
|
-
> def _extract_sequences(self, text: str) -> str:
|
|
95
|
-
> """Extract only terminal sequences from text."""
|
|
96
|
-
> result = []
|
|
97
|
-
> for segment, is_seq in iter_sequences(text):
|
|
98
|
-
> if is_seq:
|
|
99
|
-
> result.append(segment)
|
|
100
|
-
> return ''.join(result)
|
|
101
|
-
|
|
102
|
-
> def _split(self, text: str) -> list[str]: # pylint: disable=too-many-locals
|
|
103
|
-
> r"""
|
|
104
|
-
> Sequence-aware variant of :meth:`textwrap.TextWrapper._split`.
|
|
105
|
-
|
|
106
|
-
> This method ensures that terminal escape sequences don't interfere with the text splitting
|
|
107
|
-
> logic, particularly for hyphen-based word breaking. It builds a position mapping from
|
|
108
|
-
> stripped text to original text, calls the parent's _split on stripped text, then maps chunks
|
|
109
|
-
> back.
|
|
110
|
-
|
|
111
|
-
> OSC hyperlink sequences are treated as word boundaries::
|
|
112
|
-
|
|
113
|
-
> >>> wrap('foo \x1b]8;;https://example.com\x07link\x1b]8;;\x07 bar', 6)
|
|
114
|
-
> ['foo', '\x1b]8;;https://example.com\x07link\x1b]8;;\x07', 'bar']
|
|
115
|
-
|
|
116
|
-
> Both BEL (``\x07``) and ST (``\x1b\\``) terminators are supported.
|
|
117
|
-
> """
|
|
118
|
-
# pylint: disable=too-many-locals,too-many-branches
|
|
119
|
-
# Build a mapping from stripped text positions to original text positions.
|
|
120
|
-
#
|
|
121
|
-
# Track where each character ENDS so that sequences between characters
|
|
122
|
-
# attach to the following text (not preceding text). This ensures sequences
|
|
123
|
-
# aren't lost when whitespace is dropped.
|
|
124
|
-
#
|
|
125
|
-
# char_end[i] = position in original text right after the i-th stripped char
|
|
126
|
-
> char_end: list[int] = []
|
|
127
|
-
> stripped_text = ''
|
|
128
|
-
> original_pos = 0
|
|
129
|
-
> prev_was_hyperlink_close = False
|
|
130
|
-
|
|
131
|
-
> for segment, is_seq in iter_sequences(text):
|
|
132
|
-
> if not is_seq:
|
|
133
|
-
# Conditionally insert space after hyperlink close to force word boundary
|
|
134
|
-
> if prev_was_hyperlink_close and segment and not segment[0].isspace():
|
|
135
|
-
> stripped_text += ' '
|
|
136
|
-
> char_end.append(original_pos)
|
|
137
|
-
> for char in segment:
|
|
138
|
-
> original_pos += 1
|
|
139
|
-
> char_end.append(original_pos)
|
|
140
|
-
> stripped_text += char
|
|
141
|
-
> prev_was_hyperlink_close = False
|
|
142
|
-
> else:
|
|
143
|
-
> is_hyperlink_close = segment.startswith(('\x1b]8;;\x1b\\', '\x1b]8;;\x07'))
|
|
144
|
-
|
|
145
|
-
# Conditionally insert space before OSC sequences to artificially create word
|
|
146
|
-
# boundary, but *not* before hyperlink close sequences, to ensure hyperlink is
|
|
147
|
-
# terminated on the same line.
|
|
148
|
-
> if (segment.startswith('\x1b]') and stripped_text and not
|
|
149
|
-
> stripped_text[-1].isspace()):
|
|
150
|
-
> if not is_hyperlink_close:
|
|
151
|
-
> stripped_text += ' '
|
|
152
|
-
> char_end.append(original_pos)
|
|
153
|
-
|
|
154
|
-
# Escape sequences advance position but don't add to stripped text
|
|
155
|
-
> original_pos += len(segment)
|
|
156
|
-
> prev_was_hyperlink_close = is_hyperlink_close
|
|
157
|
-
|
|
158
|
-
# Add sentinel for final position
|
|
159
|
-
> char_end.append(original_pos)
|
|
160
|
-
|
|
161
|
-
# Use parent's _split on the stripped text
|
|
162
|
-
# pylint: disable-next=protected-access
|
|
163
|
-
> stripped_chunks = textwrap.TextWrapper._split(self, stripped_text)
|
|
164
|
-
|
|
165
|
-
# Handle text that contains only sequences (no visible characters).
|
|
166
|
-
# Return the sequences as a single chunk to preserve them.
|
|
167
|
-
> if not stripped_chunks and text:
|
|
168
|
-
> return [text]
|
|
169
|
-
|
|
170
|
-
# Map the chunks back to the original text with sequences
|
|
171
|
-
> result: list[str] = []
|
|
172
|
-
> stripped_pos = 0
|
|
173
|
-
> num_chunks = len(stripped_chunks)
|
|
174
|
-
|
|
175
|
-
> for idx, chunk in enumerate(stripped_chunks):
|
|
176
|
-
> chunk_len = len(chunk)
|
|
177
|
-
|
|
178
|
-
# Start is where previous character ended (or 0 for first chunk)
|
|
179
|
-
> start_orig = 0 if stripped_pos == 0 else char_end[stripped_pos - 1]
|
|
180
|
-
|
|
181
|
-
# End is where next character starts. For last chunk, use sentinel
|
|
182
|
-
# to include any trailing sequences.
|
|
183
|
-
> if idx == num_chunks - 1:
|
|
184
|
-
> end_orig = char_end[-1] # sentinel includes trailing sequences
|
|
185
|
-
> else:
|
|
186
|
-
> end_orig = char_end[stripped_pos + chunk_len - 1]
|
|
187
|
-
|
|
188
|
-
# Extract the corresponding portion from the original text
|
|
189
|
-
# Skip empty chunks (from virtual spaces inserted at OSC boundaries)
|
|
190
|
-
> if start_orig != end_orig:
|
|
191
|
-
> result.append(text[start_orig:end_orig])
|
|
192
|
-
> stripped_pos += chunk_len
|
|
193
|
-
|
|
194
|
-
> return result
|
|
195
|
-
|
|
196
|
-
> def _wrap_chunks(self, chunks: list[str]) -> list[str]: # pylint: disable=too-many-branches
|
|
197
|
-
> """
|
|
198
|
-
> Wrap chunks into lines using sequence-aware width.
|
|
199
|
-
|
|
200
|
-
> Override TextWrapper._wrap_chunks to use _width instead of len. Follows stdlib's algorithm:
|
|
201
|
-
> greedily fill lines, handle long words. Also handle OSC hyperlink processing. When
|
|
202
|
-
> hyperlinks span multiple lines, each line gets complete open/close sequences with matching
|
|
203
|
-
> id parameters for hover underlining continuity per OSC 8 spec.
|
|
204
|
-
> """
|
|
205
|
-
# pylint: disable=too-many-branches,too-many-statements,too-complex,too-many-locals
|
|
206
|
-
# pylint: disable=too-many-nested-blocks
|
|
207
|
-
# the hyperlink code in particular really pushes the complexity rating of this method.
|
|
208
|
-
# preferring to keep it "all in one method" because of so much local state and manipulation.
|
|
209
|
-
> if not chunks:
|
|
210
|
-
> return []
|
|
211
|
-
|
|
212
|
-
> if self.max_lines is not None:
|
|
213
|
-
> if self.max_lines > 1:
|
|
214
|
-
> indent = self.subsequent_indent
|
|
215
|
-
> else:
|
|
216
|
-
> indent = self.initial_indent
|
|
217
|
-
> if (self._width(indent)
|
|
218
|
-
> + self._width(self.placeholder.lstrip())
|
|
219
|
-
> > self.width):
|
|
220
|
-
> raise ValueError("placeholder too large for max width")
|
|
221
|
-
|
|
222
|
-
> lines: list[str] = []
|
|
223
|
-
> is_first_line = True
|
|
224
|
-
|
|
225
|
-
> hyperlink_state: Optional[HyperlinkParams] = None
|
|
226
|
-
# Track the id we're using for the current hyperlink continuation
|
|
227
|
-
> current_hyperlink_id: Optional[str] = None
|
|
228
|
-
|
|
229
|
-
# Arrange in reverse order so items can be efficiently popped
|
|
230
|
-
> chunks = list(reversed(chunks))
|
|
231
|
-
|
|
232
|
-
> while chunks:
|
|
233
|
-
> current_line: list[str] = []
|
|
234
|
-
> current_width = 0
|
|
235
|
-
|
|
236
|
-
# Get the indent and available width for current line
|
|
237
|
-
> indent = self.initial_indent if is_first_line else self.subsequent_indent
|
|
238
|
-
> line_width = self.width - self._width(indent)
|
|
239
|
-
|
|
240
|
-
# If continuing a hyperlink from previous line, prepend open sequence
|
|
241
|
-
> if hyperlink_state is not None:
|
|
242
|
-
> open_seq = HyperlinkParams(
|
|
243
|
-
> url=hyperlink_state.url,
|
|
244
|
-
> params=hyperlink_state.params,
|
|
245
|
-
> terminator=hyperlink_state.terminator,
|
|
246
|
-
> ).make_open()
|
|
247
|
-
> chunks[-1] = open_seq + chunks[-1]
|
|
248
|
-
|
|
249
|
-
# Drop leading whitespace (except at very start)
|
|
250
|
-
# When dropping, transfer any sequences to the next chunk.
|
|
251
|
-
# Only drop if there's actual whitespace text, not if it's only sequences.
|
|
252
|
-
> stripped = self._strip_sequences(chunks[-1])
|
|
253
|
-
> if self.drop_whitespace and lines and stripped and not stripped.strip():
|
|
254
|
-
> sequences = self._extract_sequences(chunks[-1])
|
|
255
|
-
> del chunks[-1]
|
|
256
|
-
> if sequences and chunks:
|
|
257
|
-
> chunks[-1] = sequences + chunks[-1]
|
|
258
|
-
|
|
259
|
-
# Greedily add chunks that fit
|
|
260
|
-
> while chunks:
|
|
261
|
-
> chunk = chunks[-1]
|
|
262
|
-
> chunk_width = self._width(chunk)
|
|
263
|
-
|
|
264
|
-
> if current_width + chunk_width <= line_width:
|
|
265
|
-
> current_line.append(chunks.pop())
|
|
266
|
-
> current_width += chunk_width
|
|
267
|
-
> else:
|
|
268
|
-
> break
|
|
269
|
-
|
|
270
|
-
# Handle chunk that's too long for any line
|
|
271
|
-
> if chunks and self._width(chunks[-1]) > line_width:
|
|
272
|
-
> self._handle_long_word(
|
|
273
|
-
> chunks, current_line, current_width, line_width
|
|
274
|
-
> )
|
|
275
|
-
> current_width = self._width(''.join(current_line))
|
|
276
|
-
# Remove any empty chunks left by _handle_long_word
|
|
277
|
-
> while chunks and not chunks[-1]:
|
|
278
|
-
> del chunks[-1]
|
|
279
|
-
|
|
280
|
-
# Drop trailing whitespace
|
|
281
|
-
# When dropping, transfer any sequences to the previous chunk.
|
|
282
|
-
# Only drop if there's actual whitespace text, not if it's only sequences.
|
|
283
|
-
> stripped_last = self._strip_sequences(current_line[-1]) if current_line else ''
|
|
284
|
-
> if (self.drop_whitespace and current_line and
|
|
285
|
-
> stripped_last and not stripped_last.strip()):
|
|
286
|
-
> sequences = self._extract_sequences(current_line[-1])
|
|
287
|
-
> current_width -= self._width(current_line[-1])
|
|
288
|
-
> del current_line[-1]
|
|
289
|
-
> if sequences and current_line:
|
|
290
|
-
> current_line[-1] = current_line[-1] + sequences
|
|
291
|
-
|
|
292
|
-
> if current_line:
|
|
293
|
-
# Check whether this is a normal append or max_lines
|
|
294
|
-
# truncation. Matches stdlib textwrap precedence:
|
|
295
|
-
# normal if max_lines not set, not yet reached, or no
|
|
296
|
-
# remaining visible content that would need truncation.
|
|
297
|
-
> no_more_content = (
|
|
298
|
-
> not chunks or
|
|
299
|
-
> self.drop_whitespace and
|
|
300
|
-
> len(chunks) == 1 and
|
|
301
|
-
> not self._strip_sequences(chunks[0]).strip()
|
|
302
|
-
> )
|
|
303
|
-
> if (self.max_lines is None or
|
|
304
|
-
> len(lines) + 1 < self.max_lines or
|
|
305
|
-
> no_more_content
|
|
306
|
-
> and current_width <= line_width):
|
|
307
|
-
> line_content = ''.join(current_line)
|
|
308
|
-
|
|
309
|
-
# Track hyperlink state through this line's content
|
|
310
|
-
> new_state = self._track_hyperlink_state(line_content, hyperlink_state)
|
|
311
|
-
|
|
312
|
-
# If we end inside a hyperlink, append close sequence
|
|
313
|
-
> if new_state is not None:
|
|
314
|
-
# Ensure we have an id for continuation
|
|
315
|
-
> if current_hyperlink_id is None:
|
|
316
|
-
> if 'id=' in new_state.params:
|
|
317
|
-
> current_hyperlink_id = new_state.params
|
|
318
|
-
> elif new_state.params:
|
|
319
|
-
# Prepend id to existing params. Per OSC 8 spec, params can have
|
|
320
|
-
# multiple key=value pairs separated by ':'.
|
|
321
|
-
> current_hyperlink_id = (
|
|
322
|
-
> f'id={self._next_hyperlink_id()}:{new_state.params}')
|
|
323
|
-
> else:
|
|
324
|
-
> current_hyperlink_id = f'id={self._next_hyperlink_id()}'
|
|
325
|
-
> line_content += HyperlinkParams(
|
|
326
|
-
> terminator=new_state.terminator, url='').make_close()
|
|
327
|
-
|
|
328
|
-
# Also need to inject the id into the opening
|
|
329
|
-
# sequence if it didn't have one
|
|
330
|
-
> if 'id=' not in new_state.params:
|
|
331
|
-
# Find and replace the original open sequence with one that has id
|
|
332
|
-
> old_open = HyperlinkParams(
|
|
333
|
-
> url=new_state.url,
|
|
334
|
-
> params=new_state.params,
|
|
335
|
-
> terminator=new_state.terminator,
|
|
336
|
-
> ).make_open()
|
|
337
|
-
> new_open = HyperlinkParams(
|
|
338
|
-
> url=new_state.url,
|
|
339
|
-
> params=current_hyperlink_id,
|
|
340
|
-
> terminator=new_state.terminator,
|
|
341
|
-
> ).make_open()
|
|
342
|
-
> line_content = line_content.replace(old_open, new_open, 1)
|
|
343
|
-
|
|
344
|
-
# Update state for next line, using computed id
|
|
345
|
-
> hyperlink_state = HyperlinkParams(
|
|
346
|
-
> new_state.url, current_hyperlink_id, new_state.terminator)
|
|
347
|
-
> else:
|
|
348
|
-
> hyperlink_state = None
|
|
349
|
-
> current_hyperlink_id = None # Reset id when hyperlink closes
|
|
350
|
-
|
|
351
|
-
# Strip trailing whitespace when drop_whitespace is enabled
|
|
352
|
-
# (matches CPython #140627 fix behavior)
|
|
353
|
-
> if self.drop_whitespace:
|
|
354
|
-
> line_content = line_content.rstrip()
|
|
355
|
-
> lines.append(indent + line_content)
|
|
356
|
-
> is_first_line = False
|
|
357
|
-
> else:
|
|
358
|
-
# max_lines reached with remaining content.
|
|
359
|
-
# pop chunks until placeholder fits, then break.
|
|
360
|
-
> placeholder_w = self._width(self.placeholder)
|
|
361
|
-
> while current_line:
|
|
362
|
-
> last_text = self._strip_sequences(current_line[-1])
|
|
363
|
-
> if (last_text.strip()
|
|
364
|
-
> and current_width + placeholder_w <= line_width):
|
|
365
|
-
> line_content = ''.join(current_line)
|
|
366
|
-
> new_state = self._track_hyperlink_state(
|
|
367
|
-
> line_content, hyperlink_state)
|
|
368
|
-
> if new_state is not None:
|
|
369
|
-
> line_content += HyperlinkParams(
|
|
370
|
-
> terminator=new_state.terminator, url='').make_close()
|
|
371
|
-
> lines.append(indent + line_content + self.placeholder)
|
|
372
|
-
> break
|
|
373
|
-
> current_width -= self._width(current_line[-1])
|
|
374
|
-
> del current_line[-1]
|
|
375
|
-
> else:
|
|
376
|
-
> if lines:
|
|
377
|
-
> prev_line = self._rstrip_visible(lines[-1])
|
|
378
|
-
> if (self._width(prev_line) + placeholder_w
|
|
379
|
-
> <= self.width):
|
|
380
|
-
> lines[-1] = prev_line + self.placeholder
|
|
381
|
-
> break
|
|
382
|
-
> lines.append(indent + self.placeholder.lstrip())
|
|
383
|
-
> break
|
|
384
|
-
|
|
385
|
-
> return lines
|
|
386
|
-
|
|
387
|
-
> def _track_hyperlink_state(
|
|
388
|
-
> self, text: str,
|
|
389
|
-
> state: Optional[HyperlinkParams]) -> Optional[HyperlinkParams]:
|
|
390
|
-
> """
|
|
391
|
-
> Track hyperlink state through text.
|
|
392
|
-
|
|
393
|
-
> :param text: Text to scan for hyperlink sequences.
|
|
394
|
-
> :param state: Current state or None if outside hyperlink.
|
|
395
|
-
> :returns: Updated state after processing text.
|
|
396
|
-
> """
|
|
397
|
-
> for segment, is_seq in iter_sequences(text):
|
|
398
|
-
> if is_seq:
|
|
399
|
-
> parsed_link = HyperlinkParams.parse(segment)
|
|
400
|
-
> if parsed_link is not None and parsed_link.url: # has URL = open
|
|
401
|
-
> state = parsed_link
|
|
402
|
-
> elif segment.startswith(('\x1b]8;;\x1b\\', '\x1b]8;;\x07')): # close
|
|
403
|
-
> state = None
|
|
404
|
-
> return state
|
|
405
|
-
|
|
406
|
-
> def _handle_long_word(self, reversed_chunks: list[str],
|
|
407
|
-
> cur_line: list[str], cur_len: int,
|
|
408
|
-
> width: int) -> None:
|
|
409
|
-
> """
|
|
410
|
-
> Sequence-aware :meth:`textwrap.TextWrapper._handle_long_word`.
|
|
411
|
-
|
|
412
|
-
> This method ensures that word boundaries are not broken mid-sequence, and respects grapheme
|
|
413
|
-
> cluster boundaries when breaking long words.
|
|
414
|
-
> """
|
|
415
|
-
> if width < 1:
|
|
416
|
-
> space_left = 1
|
|
417
|
-
> else:
|
|
418
|
-
> space_left = width - cur_len
|
|
419
|
-
|
|
420
|
-
> chunk = reversed_chunks[-1]
|
|
421
|
-
|
|
422
|
-
> if self.break_long_words:
|
|
423
|
-
> break_at_hyphen = False
|
|
424
|
-
> hyphen_end = 0
|
|
425
|
-
|
|
426
|
-
# Handle break_on_hyphens: find last hyphen within space_left
|
|
427
|
-
> if self.break_on_hyphens:
|
|
428
|
-
# Strip sequences to find hyphen in logical text
|
|
429
|
-
> stripped = self._strip_sequences(chunk)
|
|
430
|
-
> if len(stripped) > space_left:
|
|
431
|
-
# Find last hyphen in the portion that fits
|
|
432
|
-
> hyphen_pos = stripped.rfind('-', 0, space_left)
|
|
433
|
-
> if hyphen_pos > 0 and any(c != '-' for c in stripped[:hyphen_pos]):
|
|
434
|
-
# Map back to original position including sequences
|
|
435
|
-
> hyphen_end = self._map_stripped_pos_to_original(chunk, hyphen_pos + 1)
|
|
436
|
-
> break_at_hyphen = True
|
|
437
|
-
|
|
438
|
-
# Break at grapheme boundaries to avoid splitting multi-codepoint characters
|
|
439
|
-
> if break_at_hyphen:
|
|
440
|
-
> actual_end = hyphen_end
|
|
441
|
-
> else:
|
|
442
|
-
> actual_end = self._find_break_position(chunk, space_left)
|
|
443
|
-
# Include first visible unit when break would take only leading sequences.
|
|
444
|
-
> if not cur_line and (
|
|
445
|
-
> actual_end == 0
|
|
446
|
-
> or (actual_end < len(chunk)
|
|
447
|
-
> and self._width(chunk[:actual_end]) == 0)):
|
|
448
|
-
> actual_end = self._find_first_visible_break(chunk)
|
|
449
|
-
> cur_line.append(chunk[:actual_end])
|
|
450
|
-
> reversed_chunks[-1] = chunk[actual_end:]
|
|
451
|
-
|
|
452
|
-
> elif not cur_line:
|
|
453
|
-
> cur_line.append(reversed_chunks.pop())
|
|
454
|
-
|
|
455
|
-
> def _map_stripped_pos_to_original(self, text: str, stripped_pos: int) -> int:
|
|
456
|
-
> """Map a position in stripped text back to original text position."""
|
|
457
|
-
> stripped_idx = 0
|
|
458
|
-
> original_idx = 0
|
|
459
|
-
|
|
460
|
-
> for segment, is_seq in iter_sequences(text):
|
|
461
|
-
> if is_seq:
|
|
462
|
-
> original_idx += len(segment)
|
|
463
|
-
> elif stripped_idx + len(segment) > stripped_pos:
|
|
464
|
-
# Position is within this segment
|
|
465
|
-
> return original_idx + (stripped_pos - stripped_idx)
|
|
466
|
-
> else:
|
|
467
|
-
> stripped_idx += len(segment)
|
|
468
|
-
> original_idx += len(segment)
|
|
469
|
-
|
|
470
|
-
# Caller guarantees stripped_pos < total stripped chars, so we always
|
|
471
|
-
# return from within the loop. This line satisfies the type checker.
|
|
472
|
-
- return original_idx # pragma: no cover
|
|
473
|
-
|
|
474
|
-
> def _find_break_position(self, text: str, max_width: int) -> int:
|
|
475
|
-
> """Find string index in text that fits within max_width cells."""
|
|
476
|
-
> idx = 0
|
|
477
|
-
> width_so_far = 0
|
|
478
|
-
|
|
479
|
-
> while idx < len(text):
|
|
480
|
-
> char = text[idx]
|
|
481
|
-
|
|
482
|
-
# Skip escape sequences (they don't add width)
|
|
483
|
-
> if char == '\x1b':
|
|
484
|
-
> match = ZERO_WIDTH_PATTERN.match(text, idx)
|
|
485
|
-
> if match:
|
|
486
|
-
> idx = match.end()
|
|
487
|
-
> continue
|
|
488
|
-
|
|
489
|
-
# Get grapheme (use start= to avoid slice allocation)
|
|
490
|
-
> grapheme = next(iter_graphemes(text, start=idx))
|
|
491
|
-
|
|
492
|
-
> grapheme_width = self._width(grapheme)
|
|
493
|
-
> if width_so_far + grapheme_width > max_width:
|
|
494
|
-
> return idx # Found break point
|
|
495
|
-
|
|
496
|
-
> width_so_far += grapheme_width
|
|
497
|
-
> idx += len(grapheme)
|
|
498
|
-
|
|
499
|
-
# Caller guarantees chunk_width > max_width, so a grapheme always
|
|
500
|
-
# exceeds and we return from within the loop. Type checker requires this.
|
|
501
|
-
- return idx # pragma: no cover
|
|
502
|
-
|
|
503
|
-
> def _find_first_visible_break(self, text: str) -> int:
|
|
504
|
-
> """End of leading escape sequences plus the first grapheme."""
|
|
505
|
-
> idx = 0
|
|
506
|
-
> while idx < len(text) and text[idx] == '\x1b':
|
|
507
|
-
> match = ZERO_WIDTH_PATTERN.match(text, idx)
|
|
508
|
-
> if match is None:
|
|
509
|
-
> break
|
|
510
|
-
> idx = match.end()
|
|
511
|
-
> if idx >= len(text):
|
|
512
|
-
! return len(text)
|
|
513
|
-
> return idx + len(next(iter_graphemes(text, start=idx)))
|
|
514
|
-
|
|
515
|
-
> def _rstrip_visible(self, text: str) -> str:
|
|
516
|
-
> """Strip trailing visible whitespace, preserving trailing sequences."""
|
|
517
|
-
> segments = list(iter_sequences(text))
|
|
518
|
-
> last_vis = -1
|
|
519
|
-
> for i, (segment, is_seq) in enumerate(segments):
|
|
520
|
-
> if not is_seq and segment.rstrip():
|
|
521
|
-
> last_vis = i
|
|
522
|
-
> if last_vis == -1:
|
|
523
|
-
> return ''
|
|
524
|
-
> result = []
|
|
525
|
-
> for i, (segment, is_seq) in enumerate(segments):
|
|
526
|
-
> if i < last_vis:
|
|
527
|
-
> result.append(segment)
|
|
528
|
-
> elif i == last_vis:
|
|
529
|
-
> result.append(segment.rstrip())
|
|
530
|
-
> elif is_seq:
|
|
531
|
-
> result.append(segment)
|
|
532
|
-
> return ''.join(result)
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
> def wrap(text: str, width: int = 70, *,
|
|
536
|
-
> control_codes: Literal['parse', 'strict', 'ignore'] = 'parse',
|
|
537
|
-
> tabsize: int = 8,
|
|
538
|
-
> expand_tabs: bool = True,
|
|
539
|
-
> replace_whitespace: bool = True,
|
|
540
|
-
> ambiguous_width: int = 1,
|
|
541
|
-
> term_program: bool | str = False,
|
|
542
|
-
> initial_indent: str = '',
|
|
543
|
-
> subsequent_indent: str = '',
|
|
544
|
-
> fix_sentence_endings: bool = False,
|
|
545
|
-
> break_long_words: bool = True,
|
|
546
|
-
> break_on_hyphens: bool = True,
|
|
547
|
-
> drop_whitespace: bool = True,
|
|
548
|
-
> max_lines: Optional[int] = None,
|
|
549
|
-
> placeholder: str = ' [...]',
|
|
550
|
-
> propagate_sgr: bool = True) -> list[str]:
|
|
551
|
-
> r"""
|
|
552
|
-
> Wrap text to fit within given width, returning a list of wrapped lines.
|
|
553
|
-
|
|
554
|
-
> Like :func:`textwrap.wrap`, but measures width in display cells rather than
|
|
555
|
-
> characters, correctly handling wide characters, combining marks, and terminal
|
|
556
|
-
> escape sequences.
|
|
557
|
-
|
|
558
|
-
> :param text: Text to wrap, may contain terminal sequences.
|
|
559
|
-
> :param width: Maximum line width in display cells.
|
|
560
|
-
> :param control_codes: How to handle terminal sequences (see :func:`~.width`).
|
|
561
|
-
> :param tabsize: Tab stop width for tab expansion.
|
|
562
|
-
> :param expand_tabs: If True (default), tab characters are expanded
|
|
563
|
-
> to spaces using ``tabsize``.
|
|
564
|
-
> :param replace_whitespace: If True (default), each whitespace character
|
|
565
|
-
> is replaced with a single space after tab expansion. When False,
|
|
566
|
-
> control whitespace like ``\n`` has zero display width (unlike
|
|
567
|
-
> :func:`textwrap.wrap` which counts ``len()``), so wrap points
|
|
568
|
-
> may differ from stdlib for non-space whitespace characters.
|
|
569
|
-
> :param ambiguous_width: Width to use for East Asian Ambiguous (A)
|
|
570
|
-
> characters. Default is ``1`` (narrow). Set to ``2`` for CJK contexts.
|
|
571
|
-
> :param term_program: Terminal software identifier for table correction.
|
|
572
|
-
> ``False`` (default) disables override lookup. ``True`` reads the
|
|
573
|
-
> ``TERM_PROGRAM`` or ``TERM`` environment variable for auto-detection.
|
|
574
|
-
> Accepts a canonical terminal name matching :func:`list_term_programs`,
|
|
575
|
-
> such as from XTVERSION_, ENQ_, or ``TERM_PROGRAM``.
|
|
576
|
-
|
|
577
|
-
> .. versionadded:: 0.8.0
|
|
578
|
-
> :param initial_indent: String prepended to first line.
|
|
579
|
-
> :param subsequent_indent: String prepended to subsequent lines.
|
|
580
|
-
> :param fix_sentence_endings: If True, ensure sentences are always
|
|
581
|
-
> separated by exactly two spaces.
|
|
582
|
-
> :param break_long_words: If True, break words longer than width.
|
|
583
|
-
> :param break_on_hyphens: If True, allow breaking at hyphens.
|
|
584
|
-
> :param drop_whitespace: If True (default), whitespace at the beginning
|
|
585
|
-
> and end of each line (after wrapping but before indenting) is dropped.
|
|
586
|
-
> Set to False to preserve whitespace.
|
|
587
|
-
> :param max_lines: If set, output contains at most this many lines, with
|
|
588
|
-
> ``placeholder`` appended to the last line if the text was truncated.
|
|
589
|
-
> :param placeholder: String appended to the last line when text is
|
|
590
|
-
> truncated by ``max_lines``. Default is ``' [...]'``.
|
|
591
|
-
> :param propagate_sgr: If True (default), SGR (terminal styling) sequences
|
|
592
|
-
> are propagated across wrapped lines. Each line ends with a reset
|
|
593
|
-
> sequence and the next line begins with the active style restored.
|
|
594
|
-
> :returns: List of wrapped lines without trailing newlines.
|
|
595
|
-
|
|
596
|
-
> SGR (terminal styling) sequences are propagated across wrapped lines
|
|
597
|
-
> by default. Each line ends with a reset sequence and the next line
|
|
598
|
-
> begins with the active style restored::
|
|
599
|
-
|
|
600
|
-
> >>> wrap('\x1b[1;34mHello world\x1b[0m', width=6)
|
|
601
|
-
> ['\x1b[1;34mHello\x1b[0m', '\x1b[1;34mworld\x1b[0m']
|
|
602
|
-
|
|
603
|
-
> Set ``propagate_sgr=False`` to disable this behavior.
|
|
604
|
-
|
|
605
|
-
> Like :func:`textwrap.wrap`, newlines in the input text are treated as
|
|
606
|
-
> whitespace and collapsed. To preserve paragraph breaks, wrap each
|
|
607
|
-
> paragraph separately::
|
|
608
|
-
|
|
609
|
-
> >>> text = 'First line.\nSecond line.'
|
|
610
|
-
> >>> wrap(text, 40) # newline collapsed to space
|
|
611
|
-
> ['First line. Second line.']
|
|
612
|
-
> >>> [line for para in text.split('\n')
|
|
613
|
-
> ... for line in (wrap(para, 40) if para else [''])]
|
|
614
|
-
> ['First line.', 'Second line.']
|
|
615
|
-
|
|
616
|
-
> .. seealso::
|
|
617
|
-
|
|
618
|
-
> :func:`textwrap.wrap`, :class:`textwrap.TextWrapper`
|
|
619
|
-
> Standard library text wrapping (character-based).
|
|
620
|
-
|
|
621
|
-
> :class:`.SequenceTextWrapper`
|
|
622
|
-
> Class interface for advanced wrapping options.
|
|
623
|
-
|
|
624
|
-
> .. versionadded:: 0.3.0
|
|
625
|
-
|
|
626
|
-
> .. versionchanged:: 0.5.0
|
|
627
|
-
> Added ``propagate_sgr`` parameter (default True).
|
|
628
|
-
|
|
629
|
-
> .. versionchanged:: 0.6.0
|
|
630
|
-
> Added ``expand_tabs``, ``replace_whitespace``, ``fix_sentence_endings``,
|
|
631
|
-
> ``drop_whitespace``, ``max_lines``, and ``placeholder`` parameters.
|
|
632
|
-
|
|
633
|
-
> Example::
|
|
634
|
-
|
|
635
|
-
> >>> from wcwidth import wrap
|
|
636
|
-
> >>> wrap('hello world', 5)
|
|
637
|
-
> ['hello', 'world']
|
|
638
|
-
> >>> wrap('中文字符', 4) # CJK characters (2 cells each)
|
|
639
|
-
> ['中文', '字符']
|
|
640
|
-
> """
|
|
641
|
-
# pylint: disable=too-many-arguments,too-many-locals
|
|
642
|
-
> wrapper = SequenceTextWrapper(
|
|
643
|
-
> width=width,
|
|
644
|
-
> control_codes=control_codes,
|
|
645
|
-
> tabsize=tabsize,
|
|
646
|
-
> expand_tabs=expand_tabs,
|
|
647
|
-
> replace_whitespace=replace_whitespace,
|
|
648
|
-
> ambiguous_width=ambiguous_width,
|
|
649
|
-
> term_program=term_program,
|
|
650
|
-
> initial_indent=initial_indent,
|
|
651
|
-
> subsequent_indent=subsequent_indent,
|
|
652
|
-
> fix_sentence_endings=fix_sentence_endings,
|
|
653
|
-
> break_long_words=break_long_words,
|
|
654
|
-
> break_on_hyphens=break_on_hyphens,
|
|
655
|
-
> drop_whitespace=drop_whitespace,
|
|
656
|
-
> max_lines=max_lines,
|
|
657
|
-
> placeholder=placeholder,
|
|
658
|
-
> )
|
|
659
|
-
> lines = wrapper.wrap(text)
|
|
660
|
-
|
|
661
|
-
> if propagate_sgr:
|
|
662
|
-
> lines = _propagate_sgr(lines)
|
|
663
|
-
|
|
664
|
-
> return lines
|
/package/bin/ossiq/_internal/{ossiq-0.1.13.dist-info → cryptography-50.0.1.dist-info}/INSTALLER
RENAMED
|
File without changes
|
/package/bin/ossiq/_internal/{ossiq-0.1.13.dist-info → cryptography-50.0.1.dist-info}/REQUESTED
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/bin/ossiq/_internal/{ossiq-0.1.13.dist-info → ossiq-0.1.14.dist-info}/direct_url.json
RENAMED
|
File without changes
|
/package/bin/ossiq/_internal/{ossiq-0.1.13.dist-info → ossiq-0.1.14.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
/package/bin/ossiq/_internal/{ossiq-0.1.13.dist-info → ossiq-0.1.14.dist-info}/licenses/AUTHORS
RENAMED
|
File without changes
|