on master help sign in
feat(ui): add nbsp (non-breaking space) to rendered whitespace (#2322)
2c60798unrelentingtech
book/src/configuration.md+2−1
@@ -145,7 +145,7 @@ Options for rendering whitespace with visible characters. Use `:set whitespace.r
145| Key | Description | Default |
145| Key | Description | Default |
146|-----|-------------|---------|
146|-----|-------------|---------|
147| `render` | Whether to render whitespace. May either be `"all"` or `"none"`, or a table with sub-keys `space`, `tab`, and `newline`. | `"none"` |
147| `render` | Whether to render whitespace. May either be `"all"` or `"none"`, or a table with sub-keys `space`, `tab`, and `newline`. | `"none"` |
148−| `characters` | Literal characters to use when rendering whitespace. Sub-keys may be any of `tab`, `space` or `newline` | See example below |
148+| `characters` | Literal characters to use when rendering whitespace. Sub-keys may be any of `tab`, `space`, `nbsp` or `newline` | See example below |
149
149
150Example
150Example
151
151
@@ -160,6 +160,7 @@ newline = "none"
160
160
161[editor.whitespace.characters]
161[editor.whitespace.characters]
162space = "·"
162space = "·"
163+nbsp = "⍽"
163tab = "→"
164tab = "→"
164newline = "⏎"
165newline = "⏎"
165```
166```
helix-term/src/ui/editor.rs+12
@@ -370,6 +370,7 @@ impl EditorView {
370 " ".repeat(tab_width)
370 " ".repeat(tab_width)
371 };
371 };
372 let space = whitespace.characters.space.to_string();
372 let space = whitespace.characters.space.to_string();
373+ let nbsp = whitespace.characters.nbsp.to_string();
373 let newline = if whitespace.render.newline() == WhitespaceRenderValue::All {
374 let newline = if whitespace.render.newline() == WhitespaceRenderValue::All {
374 whitespace.characters.newline.to_string()
375 whitespace.characters.newline.to_string()
375 } else {
376 } else {
@@ -406,6 +407,14 @@ impl EditorView {
406 " "
407 " "
407 };
408 };
408
409
410+ let nbsp = if whitespace.render.nbsp() == WhitespaceRenderValue::All
411+ && text.len_chars() < end
412+ {
413+ &nbsp
414+ } else {
415+ " "
416+ };
417+
409 use helix_core::graphemes::{grapheme_width, RopeGraphemes};
418 use helix_core::graphemes::{grapheme_width, RopeGraphemes};
410
419
411 for grapheme in RopeGraphemes::new(text) {
420 for grapheme in RopeGraphemes::new(text) {
@@ -445,6 +454,9 @@ impl EditorView {
445 } else if grapheme == " " {
454 } else if grapheme == " " {
446 is_whitespace = true;
455 is_whitespace = true;
447 (space, 1)
456 (space, 1)
457+ } else if grapheme == "\u{00A0}" {
458+ is_whitespace = true;
459+ (nbsp, 1)
448 } else {
460 } else {
449 is_whitespace = false;
461 is_whitespace = false;
450 // Cow will prevent allocations if span contained in a single slice
462 // Cow will prevent allocations if span contained in a single slice
helix-view/src/editor.rs+11
@@ -288,6 +288,7 @@ pub enum WhitespaceRender {
288 Specific {
288 Specific {
289 default: Option<WhitespaceRenderValue>,
289 default: Option<WhitespaceRenderValue>,
290 space: Option<WhitespaceRenderValue>,
290 space: Option<WhitespaceRenderValue>,
291+ nbsp: Option<WhitespaceRenderValue>,
291 tab: Option<WhitespaceRenderValue>,
292 tab: Option<WhitespaceRenderValue>,
292 newline: Option<WhitespaceRenderValue>,
293 newline: Option<WhitespaceRenderValue>,
293 },
294 },
@@ -311,6 +312,14 @@ impl WhitespaceRender {
311 }
312 }
312 }
313 }
313 }
314 }
315+ pub fn nbsp(&self) -> WhitespaceRenderValue {
316+ match *self {
317+ Self::Basic(val) => val,
318+ Self::Specific { default, nbsp, .. } => {
319+ nbsp.or(default).unwrap_or(WhitespaceRenderValue::None)
320+ }
321+ }
322+ }
314 pub fn tab(&self) -> WhitespaceRenderValue {
323 pub fn tab(&self) -> WhitespaceRenderValue {
315 match *self {
324 match *self {
316 Self::Basic(val) => val,
325 Self::Basic(val) => val,
@@ -333,6 +342,7 @@ impl WhitespaceRender {
333#[serde(default)]
342#[serde(default)]
334pub struct WhitespaceCharacters {
343pub struct WhitespaceCharacters {
335 pub space: char,
344 pub space: char,
345+ pub nbsp: char,
336 pub tab: char,
346 pub tab: char,
337 pub newline: char,
347 pub newline: char,
338}
348}
@@ -341,6 +351,7 @@ impl Default for WhitespaceCharacters {
341 fn default() -> Self {
351 fn default() -> Self {
342 Self {
352 Self {
343 space: '·', // U+00B7
353 space: '·', // U+00B7
354+ nbsp: '⍽', // U+237D
344 tab: '→', // U+2192
355 tab: '→', // U+2192
345 newline: '⏎', // U+23CE
356 newline: '⏎', // U+23CE
346 }
357 }