links-notation 0.9.0__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.
- links_notation-0.9.0/MANIFEST.in +3 -0
- links_notation-0.9.0/PKG-INFO +187 -0
- links_notation-0.9.0/README.md +163 -0
- links_notation-0.9.0/links_notation/__init__.py +14 -0
- links_notation-0.9.0/links_notation/formatter.py +24 -0
- links_notation-0.9.0/links_notation/link.py +178 -0
- links_notation-0.9.0/links_notation/parser.py +350 -0
- links_notation-0.9.0/links_notation.egg-info/PKG-INFO +187 -0
- links_notation-0.9.0/links_notation.egg-info/SOURCES.txt +14 -0
- links_notation-0.9.0/links_notation.egg-info/dependency_links.txt +1 -0
- links_notation-0.9.0/links_notation.egg-info/top_level.txt +1 -0
- links_notation-0.9.0/pyproject.toml +42 -0
- links_notation-0.9.0/setup.cfg +4 -0
- links_notation-0.9.0/tests/test_api.py +81 -0
- links_notation-0.9.0/tests/test_link.py +80 -0
- links_notation-0.9.0/tests/test_single_line_parser.py +245 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: links-notation
|
|
3
|
+
Version: 0.9.0
|
|
4
|
+
Summary: Python implementation of the Lino protocol parser
|
|
5
|
+
Author-email: LinksPlatform <noreply@linksplatform.com>
|
|
6
|
+
License: Unlicense
|
|
7
|
+
Project-URL: Homepage, https://github.com/link-foundation/links-notation
|
|
8
|
+
Project-URL: Repository, https://github.com/link-foundation/links-notation
|
|
9
|
+
Project-URL: Issues, https://github.com/link-foundation/links-notation/issues
|
|
10
|
+
Keywords: lino,parser,links,notation,protocol
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: Public Domain
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Topic :: Text Processing
|
|
22
|
+
Requires-Python: >=3.8
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# Platform.Protocols.Lino - Python
|
|
26
|
+
|
|
27
|
+
[](https://pypi.org/project/platform-lino/)
|
|
28
|
+
[](https://pypi.org/project/platform-lino/)
|
|
29
|
+
[](../LICENSE)
|
|
30
|
+
|
|
31
|
+
Python implementation of the Lino (Links Notation) protocol parser.
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install platform-lino
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from platform_lino import Parser
|
|
43
|
+
|
|
44
|
+
parser = Parser()
|
|
45
|
+
links = parser.parse("papa (lovesMama: loves mama)")
|
|
46
|
+
|
|
47
|
+
# Access parsed links
|
|
48
|
+
for link in links:
|
|
49
|
+
print(link)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Usage
|
|
53
|
+
|
|
54
|
+
### Basic Parsing
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from platform_lino import Parser, format_links
|
|
58
|
+
|
|
59
|
+
parser = Parser()
|
|
60
|
+
|
|
61
|
+
# Parse simple links
|
|
62
|
+
links = parser.parse("(papa: loves mama)")
|
|
63
|
+
print(links[0].id) # 'papa'
|
|
64
|
+
print(len(links[0].values)) # 2
|
|
65
|
+
|
|
66
|
+
# Format links back to string
|
|
67
|
+
output = format_links(links)
|
|
68
|
+
print(output) # (papa: loves mama)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Working with Link Objects
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from platform_lino import Link
|
|
75
|
+
|
|
76
|
+
# Create links programmatically
|
|
77
|
+
link = Link('parent', [Link('child1'), Link('child2')])
|
|
78
|
+
print(str(link)) # (parent: child1 child2)
|
|
79
|
+
|
|
80
|
+
# Access link properties
|
|
81
|
+
print(link.id) # 'parent'
|
|
82
|
+
print(link.values[0].id) # 'child1'
|
|
83
|
+
|
|
84
|
+
# Combine links
|
|
85
|
+
combined = link.combine(Link('another'))
|
|
86
|
+
print(str(combined)) # ((parent: child1 child2) another)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Indented Syntax
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
parser = Parser()
|
|
93
|
+
|
|
94
|
+
# Parse indented notation
|
|
95
|
+
text = """3:
|
|
96
|
+
papa
|
|
97
|
+
loves
|
|
98
|
+
mama"""
|
|
99
|
+
|
|
100
|
+
links = parser.parse(text)
|
|
101
|
+
# Produces: (3: papa loves mama)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## API Reference
|
|
105
|
+
|
|
106
|
+
### Parser
|
|
107
|
+
|
|
108
|
+
The main parser class for Lino notation.
|
|
109
|
+
|
|
110
|
+
- `parse(input_text: str) -> List[Link]`: Parse Lino text into Link objects
|
|
111
|
+
|
|
112
|
+
### Link
|
|
113
|
+
|
|
114
|
+
Represents a link in Lino notation.
|
|
115
|
+
|
|
116
|
+
- `__init__(id: Optional[str] = None, values: Optional[List[Link]] = None)`
|
|
117
|
+
- `format(less_parentheses: bool = False) -> str`: Format as string
|
|
118
|
+
- `simplify() -> Link`: Simplify link structure
|
|
119
|
+
- `combine(other: Link) -> Link`: Combine with another link
|
|
120
|
+
|
|
121
|
+
### format_links
|
|
122
|
+
|
|
123
|
+
Format a list of links into Lino notation.
|
|
124
|
+
|
|
125
|
+
- `format_links(links: List[Link], less_parentheses: bool = False) -> str`
|
|
126
|
+
|
|
127
|
+
## Examples
|
|
128
|
+
|
|
129
|
+
### Doublets (2-tuple)
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
parser = Parser()
|
|
133
|
+
text = """
|
|
134
|
+
papa (lovesMama: loves mama)
|
|
135
|
+
son lovesMama
|
|
136
|
+
daughter lovesMama
|
|
137
|
+
"""
|
|
138
|
+
links = parser.parse(text)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Triplets (3-tuple)
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
text = """
|
|
145
|
+
papa has car
|
|
146
|
+
mama has house
|
|
147
|
+
(papa and mama) are happy
|
|
148
|
+
"""
|
|
149
|
+
links = parser.parse(text)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Quoted References
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
# References with special characters need quotes
|
|
156
|
+
text = '("has space": "value with: colon")'
|
|
157
|
+
links = parser.parse(text)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Development
|
|
161
|
+
|
|
162
|
+
### Running Tests
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
# Install development dependencies
|
|
166
|
+
pip install pytest
|
|
167
|
+
|
|
168
|
+
# Run tests
|
|
169
|
+
pytest
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Building
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
pip install build
|
|
176
|
+
python -m build
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
This project is released into the public domain under the [Unlicense](../LICENSE).
|
|
182
|
+
|
|
183
|
+
## Links
|
|
184
|
+
|
|
185
|
+
- [Main Repository](https://github.com/link-foundation/links-notation)
|
|
186
|
+
- [PyPI Package](https://pypi.org/project/platform-lino/)
|
|
187
|
+
- [Documentation](https://link-foundation.github.io/links-notation/)
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Platform.Protocols.Lino - Python
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/platform-lino/)
|
|
4
|
+
[](https://pypi.org/project/platform-lino/)
|
|
5
|
+
[](../LICENSE)
|
|
6
|
+
|
|
7
|
+
Python implementation of the Lino (Links Notation) protocol parser.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install platform-lino
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
from platform_lino import Parser
|
|
19
|
+
|
|
20
|
+
parser = Parser()
|
|
21
|
+
links = parser.parse("papa (lovesMama: loves mama)")
|
|
22
|
+
|
|
23
|
+
# Access parsed links
|
|
24
|
+
for link in links:
|
|
25
|
+
print(link)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
### Basic Parsing
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from platform_lino import Parser, format_links
|
|
34
|
+
|
|
35
|
+
parser = Parser()
|
|
36
|
+
|
|
37
|
+
# Parse simple links
|
|
38
|
+
links = parser.parse("(papa: loves mama)")
|
|
39
|
+
print(links[0].id) # 'papa'
|
|
40
|
+
print(len(links[0].values)) # 2
|
|
41
|
+
|
|
42
|
+
# Format links back to string
|
|
43
|
+
output = format_links(links)
|
|
44
|
+
print(output) # (papa: loves mama)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Working with Link Objects
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from platform_lino import Link
|
|
51
|
+
|
|
52
|
+
# Create links programmatically
|
|
53
|
+
link = Link('parent', [Link('child1'), Link('child2')])
|
|
54
|
+
print(str(link)) # (parent: child1 child2)
|
|
55
|
+
|
|
56
|
+
# Access link properties
|
|
57
|
+
print(link.id) # 'parent'
|
|
58
|
+
print(link.values[0].id) # 'child1'
|
|
59
|
+
|
|
60
|
+
# Combine links
|
|
61
|
+
combined = link.combine(Link('another'))
|
|
62
|
+
print(str(combined)) # ((parent: child1 child2) another)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Indented Syntax
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
parser = Parser()
|
|
69
|
+
|
|
70
|
+
# Parse indented notation
|
|
71
|
+
text = """3:
|
|
72
|
+
papa
|
|
73
|
+
loves
|
|
74
|
+
mama"""
|
|
75
|
+
|
|
76
|
+
links = parser.parse(text)
|
|
77
|
+
# Produces: (3: papa loves mama)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## API Reference
|
|
81
|
+
|
|
82
|
+
### Parser
|
|
83
|
+
|
|
84
|
+
The main parser class for Lino notation.
|
|
85
|
+
|
|
86
|
+
- `parse(input_text: str) -> List[Link]`: Parse Lino text into Link objects
|
|
87
|
+
|
|
88
|
+
### Link
|
|
89
|
+
|
|
90
|
+
Represents a link in Lino notation.
|
|
91
|
+
|
|
92
|
+
- `__init__(id: Optional[str] = None, values: Optional[List[Link]] = None)`
|
|
93
|
+
- `format(less_parentheses: bool = False) -> str`: Format as string
|
|
94
|
+
- `simplify() -> Link`: Simplify link structure
|
|
95
|
+
- `combine(other: Link) -> Link`: Combine with another link
|
|
96
|
+
|
|
97
|
+
### format_links
|
|
98
|
+
|
|
99
|
+
Format a list of links into Lino notation.
|
|
100
|
+
|
|
101
|
+
- `format_links(links: List[Link], less_parentheses: bool = False) -> str`
|
|
102
|
+
|
|
103
|
+
## Examples
|
|
104
|
+
|
|
105
|
+
### Doublets (2-tuple)
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
parser = Parser()
|
|
109
|
+
text = """
|
|
110
|
+
papa (lovesMama: loves mama)
|
|
111
|
+
son lovesMama
|
|
112
|
+
daughter lovesMama
|
|
113
|
+
"""
|
|
114
|
+
links = parser.parse(text)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Triplets (3-tuple)
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
text = """
|
|
121
|
+
papa has car
|
|
122
|
+
mama has house
|
|
123
|
+
(papa and mama) are happy
|
|
124
|
+
"""
|
|
125
|
+
links = parser.parse(text)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Quoted References
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
# References with special characters need quotes
|
|
132
|
+
text = '("has space": "value with: colon")'
|
|
133
|
+
links = parser.parse(text)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Development
|
|
137
|
+
|
|
138
|
+
### Running Tests
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# Install development dependencies
|
|
142
|
+
pip install pytest
|
|
143
|
+
|
|
144
|
+
# Run tests
|
|
145
|
+
pytest
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Building
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
pip install build
|
|
152
|
+
python -m build
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
This project is released into the public domain under the [Unlicense](../LICENSE).
|
|
158
|
+
|
|
159
|
+
## Links
|
|
160
|
+
|
|
161
|
+
- [Main Repository](https://github.com/link-foundation/links-notation)
|
|
162
|
+
- [PyPI Package](https://pypi.org/project/platform-lino/)
|
|
163
|
+
- [Documentation](https://link-foundation.github.io/links-notation/)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Platform.Protocols.Lino - Python implementation
|
|
3
|
+
|
|
4
|
+
Lino (Links Notation) is a simple, intuitive format for representing
|
|
5
|
+
structured data as links between references.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .link import Link
|
|
9
|
+
from .parser import Parser
|
|
10
|
+
from .formatter import format_links
|
|
11
|
+
|
|
12
|
+
__version__ = "0.7.0"
|
|
13
|
+
|
|
14
|
+
__all__ = ["Link", "Parser", "format_links"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Formatter for Lino notation.
|
|
3
|
+
|
|
4
|
+
Provides utilities for formatting Link objects back into Lino notation strings.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import List
|
|
8
|
+
from .link import Link
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def format_links(links: List[Link], less_parentheses: bool = False) -> str:
|
|
12
|
+
"""
|
|
13
|
+
Format a list of links into Lino notation.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
links: List of Link objects to format
|
|
17
|
+
less_parentheses: If True, omit parentheses where safe
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Formatted string in Lino notation
|
|
21
|
+
"""
|
|
22
|
+
if not links:
|
|
23
|
+
return ''
|
|
24
|
+
return '\n'.join(link.format(less_parentheses) for link in links)
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Link class representing a Lino link with optional ID and values.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Link:
|
|
9
|
+
"""
|
|
10
|
+
Represents a link in Lino notation.
|
|
11
|
+
|
|
12
|
+
A link can be:
|
|
13
|
+
- A simple reference (id only, no values)
|
|
14
|
+
- A link with id and values
|
|
15
|
+
- A link with only values (no id)
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, link_id: Optional[str] = None, values: Optional[List['Link']] = None):
|
|
19
|
+
"""
|
|
20
|
+
Initialize a Link.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
link_id: Optional identifier for the link
|
|
24
|
+
values: Optional list of child links
|
|
25
|
+
"""
|
|
26
|
+
self.id = link_id
|
|
27
|
+
self.values = values if values is not None else []
|
|
28
|
+
self._is_from_path_combination = False
|
|
29
|
+
|
|
30
|
+
def __str__(self) -> str:
|
|
31
|
+
"""String representation using standard formatting."""
|
|
32
|
+
return self.format(False)
|
|
33
|
+
|
|
34
|
+
def __repr__(self) -> str:
|
|
35
|
+
"""Developer-friendly representation."""
|
|
36
|
+
return f"Link(id={self.id!r}, values={self.values!r})"
|
|
37
|
+
|
|
38
|
+
def __eq__(self, other) -> bool:
|
|
39
|
+
"""Check equality with another Link."""
|
|
40
|
+
if not isinstance(other, Link):
|
|
41
|
+
return False
|
|
42
|
+
if self.id != other.id:
|
|
43
|
+
return False
|
|
44
|
+
if len(self.values) != len(other.values):
|
|
45
|
+
return False
|
|
46
|
+
return all(v1 == v2 for v1, v2 in zip(self.values, other.values))
|
|
47
|
+
|
|
48
|
+
def get_values_string(self) -> str:
|
|
49
|
+
"""Get formatted string of all values."""
|
|
50
|
+
if not self.values:
|
|
51
|
+
return ''
|
|
52
|
+
return ' '.join(Link.get_value_string(v) for v in self.values)
|
|
53
|
+
|
|
54
|
+
def simplify(self) -> 'Link':
|
|
55
|
+
"""
|
|
56
|
+
Simplify the link structure.
|
|
57
|
+
- If no values, return self
|
|
58
|
+
- If single value, return that value
|
|
59
|
+
- Otherwise return new Link with simplified values
|
|
60
|
+
"""
|
|
61
|
+
if not self.values:
|
|
62
|
+
return self
|
|
63
|
+
elif len(self.values) == 1:
|
|
64
|
+
return self.values[0]
|
|
65
|
+
else:
|
|
66
|
+
new_values = [v.simplify() for v in self.values]
|
|
67
|
+
return Link(self.id, new_values)
|
|
68
|
+
|
|
69
|
+
def combine(self, other: 'Link') -> 'Link':
|
|
70
|
+
"""Combine this link with another to create a compound link."""
|
|
71
|
+
return Link(None, [self, other])
|
|
72
|
+
|
|
73
|
+
@staticmethod
|
|
74
|
+
def get_value_string(value: 'Link') -> str:
|
|
75
|
+
"""Get string representation of a value."""
|
|
76
|
+
return value.to_link_or_id_string()
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def escape_reference(reference: Optional[str]) -> str:
|
|
80
|
+
"""
|
|
81
|
+
Escape a reference string if it contains special characters.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
reference: The reference string to escape
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
Escaped reference with quotes if needed
|
|
88
|
+
"""
|
|
89
|
+
if not reference or not reference.strip():
|
|
90
|
+
return ''
|
|
91
|
+
|
|
92
|
+
# Check if single quotes are needed
|
|
93
|
+
needs_single_quotes = any(c in reference for c in [':', '(', ')', ' ', '\t', '\n', '\r', '"'])
|
|
94
|
+
|
|
95
|
+
if needs_single_quotes:
|
|
96
|
+
return f"'{reference}'"
|
|
97
|
+
elif "'" in reference:
|
|
98
|
+
return f'"{reference}"'
|
|
99
|
+
else:
|
|
100
|
+
return reference
|
|
101
|
+
|
|
102
|
+
def to_link_or_id_string(self) -> str:
|
|
103
|
+
"""Convert to string, using just ID if no values, otherwise full format."""
|
|
104
|
+
if not self.values:
|
|
105
|
+
return Link.escape_reference(self.id) if self.id is not None else ''
|
|
106
|
+
return str(self)
|
|
107
|
+
|
|
108
|
+
def format(self, less_parentheses: bool = False, is_compound_value: bool = False) -> str:
|
|
109
|
+
"""
|
|
110
|
+
Format the link as a string.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
less_parentheses: If True, omit parentheses when safe
|
|
114
|
+
is_compound_value: If True, this is a value in a compound link
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Formatted string representation
|
|
118
|
+
"""
|
|
119
|
+
# Empty link
|
|
120
|
+
if self.id is None and not self.values:
|
|
121
|
+
return '' if less_parentheses else '()'
|
|
122
|
+
|
|
123
|
+
# Link with only ID, no values
|
|
124
|
+
if not self.values:
|
|
125
|
+
escaped_id = Link.escape_reference(self.id)
|
|
126
|
+
# When used as a value in a compound link, wrap in parentheses
|
|
127
|
+
if is_compound_value:
|
|
128
|
+
return f'({escaped_id})'
|
|
129
|
+
return escaped_id if (less_parentheses and not self.needs_parentheses(self.id)) else f'({escaped_id})'
|
|
130
|
+
|
|
131
|
+
# Format values recursively
|
|
132
|
+
values_str = ' '.join(self.format_value(v) for v in self.values)
|
|
133
|
+
|
|
134
|
+
# Link with values only (null id)
|
|
135
|
+
if self.id is None:
|
|
136
|
+
if less_parentheses:
|
|
137
|
+
# Check if all values are simple (no nested values)
|
|
138
|
+
all_simple = all(not v.values for v in self.values)
|
|
139
|
+
if all_simple:
|
|
140
|
+
# Format each value without extra wrapping
|
|
141
|
+
return ' '.join(Link.escape_reference(v.id) for v in self.values)
|
|
142
|
+
# For mixed or complex values, return without outer wrapper
|
|
143
|
+
return values_str
|
|
144
|
+
# For normal mode, wrap in parentheses
|
|
145
|
+
return f'({values_str})'
|
|
146
|
+
|
|
147
|
+
# Link with ID and values
|
|
148
|
+
id_str = Link.escape_reference(self.id)
|
|
149
|
+
with_colon = f'{id_str}: {values_str}'
|
|
150
|
+
return with_colon if (less_parentheses and not self.needs_parentheses(self.id)) else f'({with_colon})'
|
|
151
|
+
|
|
152
|
+
def format_value(self, value: 'Link') -> str:
|
|
153
|
+
"""
|
|
154
|
+
Format a single value within this link.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
value: The value link to format
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
Formatted string for the value
|
|
161
|
+
"""
|
|
162
|
+
# Check if we're in a compound link from path combinations
|
|
163
|
+
is_compound_from_paths = self._is_from_path_combination
|
|
164
|
+
|
|
165
|
+
# For compound links from paths, format values with parentheses
|
|
166
|
+
if is_compound_from_paths:
|
|
167
|
+
return value.format(False, True)
|
|
168
|
+
|
|
169
|
+
# Simple link with just an ID - don't wrap in parentheses when used as a value
|
|
170
|
+
if not value.values:
|
|
171
|
+
return Link.escape_reference(value.id)
|
|
172
|
+
|
|
173
|
+
# Complex value with its own structure - format it normally with parentheses
|
|
174
|
+
return value.format(False, False)
|
|
175
|
+
|
|
176
|
+
def needs_parentheses(self, s: Optional[str]) -> bool:
|
|
177
|
+
"""Check if a string needs to be wrapped in parentheses."""
|
|
178
|
+
return s and any(c in s for c in [' ', ':', '(', ')'])
|