Skip to content

feat(docs): add docs.appendMarkdown for formatted writes without index math#401

Open
matheusrmorgado wants to merge 3 commits into
gemini-cli-extensions:mainfrom
matheusrmorgado:feat/docs-append-markdown
Open

feat(docs): add docs.appendMarkdown for formatted writes without index math#401
matheusrmorgado wants to merge 3 commits into
gemini-cli-extensions:mainfrom
matheusrmorgado:feat/docs-append-markdown

Conversation

@matheusrmorgado

Copy link
Copy Markdown

Summary

Fixes #400. Adds docs.appendMarkdown(documentId, markdown, tabId?): converts markdown into natively formatted Docs content in a single call.

docs.appendMarkdown({
  documentId: "...",
  markdown: "# Status\n\nShipping **on time**.\n\n- item one\n- item two"
})

Today the only way to produce formatted content is the two-step docs.writeText + docs.formatText flow, where the model hand-computes 1-based character indices (the google-docs skill spends most of its length teaching that arithmetic). For agents, markdown is the native output format — this removes the index math entirely.

Design

  • Pure parser module (utils/markdown.ts): blocks (headings 1-6, bullets, numbered, paragraphs, horizontal rules) with inline formats (**bold**, *italic*/_italic_, ~~strikethrough~~, `code`, [links](url)) recorded as character ranges over the stripped text. Single-pass, non-nesting semantics, documented in the module.
  • Two batchUpdates total: one insertText with the full stripped text, then one batch of updateParagraphStyle / updateTextStyle / createParagraphBullets requests computed from parse offsets. Consecutive list items of the same kind merge into single bullet ranges.
  • tabId optional with the same convention/discovery as docs.writeText (flattened tab walk incl. child tabs; clear Tab with ID x not found error).
  • Graceful degradation, explicit in the tool description: horizontal rules are skipped (no Docs API request exists for them) and counted in the response; tables are not parsed and fall through as plain paragraphs.
  • No new OAuth scopes (documents already covers it). Registered in the docs.write feature group.

docs.formatText remains the right tool for fine-grained edits to existing text; this covers the much more common "write new formatted content" path.

What's included

  • utils/markdown.ts parser + DocsService.appendMarkdown following the existing service conventions (logging, isError shape, TABS_FIELD_MASK reuse)
  • Tool registration with Zod schema
  • 16 Jest tests: 11 parser tests (inline markers incl. unclosed/empty edge cases, links, heading levels, list items with leading whitespace, hr, pipe-row fall-through, mixed document) and 5 service tests (exact request shapes incl. computed ranges, tabId threading, tab-not-found, hr-only short-circuit, error path)
  • docs/index.md entry

Verification

npm run test && npm run lint && npm run format:check && npx tsc --noEmit --project workspace-server

All passing: 30 suites, 635 tests (619 existing + 16 new), eslint/prettier/tsc clean.

Made with Cursor

@google-cla

google-cla Bot commented Jun 12, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the docs.appendMarkdown tool, allowing users to append markdown-formatted content directly to a Google Doc as natively formatted text. It includes a custom markdown parser utility and corresponding unit tests. The review feedback highlights a bug where appending to a non-empty document merges the first markdown block with the existing text, suggesting prepending a newline when insertAt > 1 and updating the affected tests. Additionally, it is recommended to support __ for bold text formatting to better align with standard markdown conventions.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread workspace-server/src/services/DocsService.ts Outdated
Comment thread workspace-server/src/__tests__/services/DocsService.test.ts Outdated
Comment thread workspace-server/src/utils/markdown.ts
…x math

Implements gemini-cli-extensions#400. Converts a markdown string into natively formatted Docs
content in one call: headings (#-######), bold, italic, strikethrough,
inline code, links, bullet and numbered lists. A pure parser module
(utils/markdown.ts) produces blocks with inline-format ranges over stripped
plain text; the service issues one insertText followed by one batchUpdate
whose updateParagraphStyle / updateTextStyle / createParagraphBullets
requests are computed from parse offsets, so character-index arithmetic
never reaches the model. Optional tabId follows the docs.writeText
convention. Horizontal rules are skipped with a count in the response
(no Docs API request exists for them); tables degrade to plain paragraphs.
No new OAuth scopes.
…_bold__ support

Addresses gemini-code-assist review: when appending to a non-empty body,
insertAt sits just before the last paragraph's final newline, so the first
markdown block merged into that paragraph and its block style leaked onto
existing text; a prepended newline (with offsets shifted accordingly) keeps
appends isolated. Also adds __double-underscore__ bold per standard
markdown, with parser coverage.
Refinement mirrored from downstream review of the same logic: keying the
prefix off insertAt > 1 also prepended a newline when the body already ended
in an empty paragraph, leaving a stray blank line between existing content
and the appended markdown. Now keyed off the last element's startIndex
(separator only when inserting inside a non-empty last paragraph), with a
test pinning the empty-trailing-paragraph case and realistic startIndex in
the existing mocks.
@matheusrmorgado matheusrmorgado force-pushed the feat/docs-append-markdown branch from 33fb763 to f8ed5c9 Compare June 12, 2026 21:23
@bdoyle0182

Copy link
Copy Markdown

appendMarkdown as a dedicated individual tool seems odd. I would try to propose something more akin to formatting that is generic and markdown as a param to the tool is just one option for the model to format the input

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: docs.appendMarkdown — write formatted Docs content without manual index math

2 participants