Shopify / Shopify/cli-ui

Truncater counts OSC sequence contents (hyperlinks) as printable width

Open
#614 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Ruby
Stars
1.1k
Forks
57
Avg merge
2h 55m
Merged PRs (30d)
2

Description

Description

The CLI::UI::Truncater correctly skips CSI sequences (\x1b[...) when calculating printable width, but it doesn't handle OSC sequences (\x1b]...). This causes strings containing hyperlinks to be truncated much more aggressively than expected, since the URL inside the hyperlink escape codes is counted as printable characters.

Reproduction
require 'cli/ui'

# Create a hyperlink
url = "https://github.com/Shopify/shopify/pull/12345"
link = CLI::UI.link(url, "#12345")  # displays as "#12345" but links to full URL

puts "Link string: #{link.inspect}"
puts "Printing width (ANSI.printing_width): #{CLI::UI::ANSI.printing_width(link)}"

# Try to truncate to 20 chars - should be plenty for "#12345"
truncated = CLI::UI::Truncater.call(link, 20)
puts "Truncated to 20: #{truncated.inspect}"
Expected behavior
  • ANSI.printing_width correctly returns 6 (the length of #12345)
  • Truncater.call(link, 20) should return the original string unchanged since #12345 is only 6 characters
Actual behavior
  • ANSI.printing_width correctly returns 6
  • Truncater.call(link, 20) truncates the string because it counts 8;;https://github.com/Shopify/shopify/pull/12345 (the URL inside the OSC sequence) as printable characters
Root cause

In lib/cli/ui/truncater.rb, the escape sequence parser only handles CSI sequences:

when PARSE_ESC
  mode = case cp
  when LEFT_SQUARE_BRACKET  # 0x5b = '['
    PARSE_ANSI
  else
    PARSE_ROOT  # <-- OSC sequences start with ']' (0x5d), so they fall through here
  end

OSC sequences have the format \x1b]...ST where ST is either \x07 (BEL) or \x1b\ (ESC + backslash). Since the Truncater doesn't recognize ] after ESC, it returns to PARSE_ROOT and counts the OSC content as visible characters.

Impact

This affects any use of CLI::UI::SpinGroup (spinners) with hyperlinks in titles. The spinner uses Truncater to fit titles to terminal width, causing hyperlink titles to be truncated far more than necessary.

Example output with a hyperlink in a spinner title:

┃ ⚠ https://github.com/Shop…

Even though there's plenty of terminal width remaining, the title is truncated because the hidden URL is counted.

Suggested fix

Add OSC sequence handling to the Truncater, similar to how ANSI.strip_codes already handles it:

RIGHT_SQUARE_BRACKET = 0x5d  # ]
BACKSLASH = 0x5c  # \
BEL = 0x07

# In the parser:
when PARSE_ESC
  mode = case cp
  when LEFT_SQUARE_BRACKET
    PARSE_ANSI
  when RIGHT_SQUARE_BRACKET
    PARSE_OSC  # New state for OSC sequences
  else
    PARSE_ROOT
  end

when PARSE_OSC
  # OSC sequences end with BEL or ESC+backslash
  case cp
  when BEL
    mode = PARSE_ROOT
  when ESC
    mode = PARSE_OSC_END
  end

when PARSE_OSC_END
  # Expecting backslash to complete ST
  mode = PARSE_ROOT

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in lib/cli/ui/truncater.rb and compare its escape-sequence parsing with the OSC handling in ANSI.strip_codes. Update truncation so hyperlink URLs between OSC delimiters do not count toward printable width, then verify the reproduction: the hyperlink displaying as #12345 remains unchanged when truncated to 20 characters.

Written by the indexing model from the issue text.

Assessment

Tech stack
ruby
Domain
cli
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.