Skip to content

Google Docs: paragraph breaks are lost, so getParagraphs splits in the wrong places #588

Description

@kcarnold

extractTextOnly (google-docs-addon/Code.gs:200) accumulates document text with no separator between children:

const childText = child.asText ? child.asText() : null;
if (childText) {
  text += childText.getText();
}

A paragraph's getText() carries no trailing newline, so real paragraph breaks disappear from the string. googleDocsEditorAPI.getParagraphs then reconstructs paragraphs by splitting that text on \n:

const text = `${ctx.beforeCursor || ''}${ctx.selectedText || ''}${ctx.afterCursor || ''}`;
return text.split('\n');

The result is inverted: it splits at soft line breaks inside a paragraph (which do survive as \n) and joins across the real paragraph boundaries.

Impact

Paragraphs are the coordinate system for the whole My Words feature — view's [n] numbering, insert/move targeting, and every ParagraphSplice. On Google Docs that coordinate system does not correspond to the document.

It also corrupts the word-bank corpus independently of any editing: with no separator, the last word of one paragraph and the first word of the next fuse into a single token (…decidedThe next…), which is a word the writer never wrote, while their real boundary adjacency is lost.

Anything reading getDocText for context — not just My Words — sees the same run-together text.

Fix

Join children with \n in extractTextOnly, and keep getParagraphs's split in agreement with it. Worth deciding at the same time whether soft line breaks should be paragraph boundaries for view purposes (probably not) — if not, they need distinguishing from real breaks rather than both arriving as \n.

Confidence

Read from source; not executed. Apps Script can't be run from the dev container, so this wants confirming in a live document before or alongside the fix — including whether Element.asText() on a PARAGRAPH child succeeds or throws into the catch (e) { continue; } above it, which would mean whole paragraphs are being skipped rather than merely joined.

Found while making text matching typography-tolerant (#587); not caused by it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions