gpui: Fix text wrapping for URLs (#35724)

Close #35715

Release Notes:

- Fixed to wrap long URLs in editor.

<img width="836" height="740" alt="image"
src="https://github.com/user-attachments/assets/635ce792-5f19-4c76-b131-0d270d09b103"
/>

I remember when I was working on CJK line wrapping support in the early
days, I considered making `\` a line wrapping character, but for some
reason it was on the list of characters that were not allowed to wrap.

In reference to VS Code, it looks like `&`, `/`, `?` should wrap, so I
removed all of them.

---------

Co-authored-by: Mikayla Maki <mikayla@zed.dev>
This commit is contained in:
Jason Lee
2025-10-16 23:06:14 -07:00
committed by GitHub
co-authored by Mikayla Maki
parent e67065f2a3
commit 6c3a7f6ddb
2 changed files with 16 additions and 7 deletions
+5 -1
View File
@@ -7,7 +7,11 @@ struct HelloWorld {}
impl Render for HelloWorld {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
let text = "The longest word 你好世界这段是中文,こんにちはこの段落は日本語です in any of the major English language dictionaries is pneumonoultramicroscopicsilicovolcanoconiosis, a word that refers to a lung disease contracted from the inhalation of very fine silica particles, specifically from a volcano; medically, it is the same as silicosis.";
let text = "The longest word 你好世界这段是中文,こんにちはこの段落は日本語です in any of the major \
English language dictionaries is pneumonoultramicroscopicsilicovolcanoconiosis, a word that \
refers to a lung disease contracted from the inhalation of very fine silica particles, \
a url https://github.com/zed-industries/zed/pull/35724?query=foo&bar=2, \
specifically from a volcano; medically, it is the same as silicosis.";
div()
.id("page")
.size_full()
+11 -6
View File
@@ -163,6 +163,8 @@ impl LineWrapper {
line
}
/// Any character in this list should be treated as a word character,
/// meaning it can be part of a word that should not be wrapped.
pub(crate) fn is_word_char(c: char) -> bool {
// ASCII alphanumeric characters, for English, numbers: `Hello123`, etc.
c.is_ascii_alphanumeric() ||
@@ -180,10 +182,9 @@ impl LineWrapper {
// https://en.wikipedia.org/wiki/Cyrillic_script_in_Unicode
matches!(c, '\u{0400}'..='\u{04FF}') ||
// Some other known special characters that should be treated as word characters,
// e.g. `a-b`, `var_name`, `I'm`, '@mention`, `#hashtag`, `100%`, `3.1415`, `2^3`, `a~b`, etc.
matches!(c, '-' | '_' | '.' | '\'' | '$' | '%' | '@' | '#' | '^' | '~' | ',' | '!' | ';' | '*') ||
// Characters that used in URL, e.g. `https://github.com/zed-industries/zed?a=1&b=2` for better wrapping a long URL.
matches!(c, '/' | ':' | '?' | '&' | '=') ||
// e.g. `a-b`, `var_name`, `I'm`, '@mention`, `#hashtag`, `100%`, `3.1415`,
// `2^3`, `a~b`, `a=1`, `Self::new`, etc.
matches!(c, '-' | '_' | '.' | '\'' | '$' | '%' | '@' | '#' | '^' | '~' | ',' | '=' | ':') ||
// `⋯` character is special used in Zed, to keep this at the end of the line.
matches!(c, '⋯')
}
@@ -644,15 +645,19 @@ mod tests {
assert_word("@mention");
assert_word("#hashtag");
assert_word("$variable");
assert_word("a=1");
assert_word("Self::is_word_char");
assert_word("more⋯");
// Space
assert_not_word("foo bar");
// URL case
assert_word("https://github.com/zed-industries/zed/");
assert_word("github.com");
assert_word("a=1&b=2");
assert_not_word("zed-industries/zed");
assert_not_word("zed-industries\\zed");
assert_not_word("a=1&b=2");
assert_not_word("foo?b=2");
// Latin-1 Supplement
assert_word("ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ");