diff --git a/lib/tickers.py b/lib/tickers.py
index 995ffca..5bcb075 100644
--- a/lib/tickers.py
+++ b/lib/tickers.py
@@ -19,7 +19,9 @@
PROTECTED_TAG_RE = re.compile(r"<(/?)(a|code|pre)\b", re.I)
BOLD_TAG_RE = re.compile(r"<(/?)(b|strong)\b", re.I)
URL_RE = re.compile(r'https?://[^\s<>"]+')
-RAW_ANCHOR_RE = re.compile(r'\s*https?://[^<]*')
+_CITE = r'\[\d+\]'
+CITE_ONLY_RUN_RE = re.compile(rf"\s*\n\s*({_CITE}(?:\s+{_CITE})*)[ \t]*(?=\n|$)") # lines holding only citations
+RAW_ANCHOR_RE =re.compile(r'\s*https?://[^<]*')
# "Micron (MU)": up to four capitalised words (or a number) right before a parenthesised ticker.
_WORD = r"[A-Z0-9][\w&'ā-]*(?:\.[\w&'ā-]+)*"
NAME_TICKER_RE = re.compile(
@@ -94,7 +96,9 @@ def cite(m: re.Match) -> str:
return f'[{n}]{tail}'
text = RAW_ANCHOR_RE.sub(lambda m: m.group(1), text)
- return _rewrite(text, lambda seg, bold: URL_RE.sub(cite, seg))
+ text = _rewrite(text, lambda seg, bold: URL_RE.sub(cite, seg))
+ # Links the model put on their own lines join the text before them: "volume.[1][2]"
+ return CITE_ONLY_RUN_RE.sub(lambda m: re.sub(r"(?<=)\s+", "", m.group(1)), text)
def link_tickers(text: str) -> str:
diff --git a/tests/test_tickers.py b/tests/test_tickers.py
index d78890c..c922e70 100644
--- a/tests/test_tickers.py
+++ b/tests/test_tickers.py
@@ -58,6 +58,14 @@ def test_raw_links_go_behind_citation_numbers():
assert "quote/NVDA" not in out # the ticker inside the URL is not linked
+def test_citations_on_their_own_lines_join_the_preceding_text():
+ a, b = '[1]', '[2]'
+ assert link_tickers("Thin volume.\n\nhttps://a.com/1\nhttps://b.com/2") == f"Thin volume.{a}{b}"
+ assert link_tickers("One.\n\nhttps://a.com/1\n\nTwo.\nhttps://b.com/2") == f"One.{a}\n\nTwo.{b}"
+ assert link_tickers("Said https://a.com/1 then more") == f"Said {a} then more" # inline: untouched
+ assert link_tickers("Thin.\nhttps://a.com/1 and more") == f"Thin.\n{a} and more" # not a citation-only line
+
+
def test_link_labelled_with_its_own_url_is_numbered_but_named_links_and_code_are_not():
assert link_tickers('https://y.com/p⦠ok') == '[1] ok'
assert link_tickers('Reuters') == 'Reuters'