@@ -148,6 +148,8 @@ pub struct Config {
148148 pub lsp: LspConfig,
149149 /// Column numbers at which to draw the rulers. Default to `[]`, meaning no rulers.
150150 pub rulers: Vec<u16>,
151+ #[serde(default)]
152+ pub whitespace: WhitespaceConfig,
151153}
152154
153155#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
@@ -263,6 +265,88 @@ impl std::str::FromStr for GutterType {
263265 }
264266}
265267
268+#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
269+#[serde(default)]
270+pub struct WhitespaceConfig {
271+ pub render: WhitespaceRender,
272+ pub characters: WhitespaceCharacters,
273+}
274+
275+impl Default for WhitespaceConfig {
276+ fn default() -> Self {
277+ Self {
278+ render: WhitespaceRender::Basic(WhitespaceRenderValue::None),
279+ characters: WhitespaceCharacters::default(),
280+ }
281+ }
282+}
283+
284+#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
285+#[serde(untagged, rename_all = "kebab-case")]
286+pub enum WhitespaceRender {
287+ Basic(WhitespaceRenderValue),
288+ Specific {
289+ default: Option<WhitespaceRenderValue>,
290+ space: Option<WhitespaceRenderValue>,
291+ tab: Option<WhitespaceRenderValue>,
292+ newline: Option<WhitespaceRenderValue>,
293+ },
294+}
295+
296+#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
297+#[serde(rename_all = "kebab-case")]
298+pub enum WhitespaceRenderValue {
299+ None,
300+ // TODO
301+ // Selection,
302+ All,
303+}
304+
305+impl WhitespaceRender {
306+ pub fn space(&self) -> WhitespaceRenderValue {
307+ match *self {
308+ Self::Basic(val) => val,
309+ Self::Specific { default, space, .. } => {
310+ space.or(default).unwrap_or(WhitespaceRenderValue::None)
311+ }
312+ }
313+ }
314+ pub fn tab(&self) -> WhitespaceRenderValue {
315+ match *self {
316+ Self::Basic(val) => val,
317+ Self::Specific { default, tab, .. } => {
318+ tab.or(default).unwrap_or(WhitespaceRenderValue::None)
319+ }
320+ }
321+ }
322+ pub fn newline(&self) -> WhitespaceRenderValue {
323+ match *self {
324+ Self::Basic(val) => val,
325+ Self::Specific {
326+ default, newline, ..
327+ } => newline.or(default).unwrap_or(WhitespaceRenderValue::None),
328+ }
329+ }
330+}
331+
332+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
333+#[serde(default)]
334+pub struct WhitespaceCharacters {
335+ pub space: char,
336+ pub tab: char,
337+ pub newline: char,
338+}
339+
340+impl Default for WhitespaceCharacters {
341+ fn default() -> Self {
342+ Self {
343+ space: '·', // U+00B7
344+ tab: '→', // U+2192
345+ newline: '⏎', // U+23CE
346+ }
347+ }
348+}
349+
266350impl Default for Config {
267351 fn default() -> Self {
268352 Self {
@@ -288,6 +372,7 @@ impl Default for Config {
288372 search: SearchConfig::default(),
289373 lsp: LspConfig::default(),
290374 rulers: Vec::new(),
375+ whitespace: WhitespaceConfig::default(),
291376 }
292377 }
293378}
@@ -366,7 +451,7 @@ pub struct Editor {
366451#[derive(Debug, Clone)]
367452pub enum ConfigEvent {
368453 Refresh,
369− Update(Config),
454+ Update(Box<Config>),
370455}
371456
372457#[derive(Debug, Clone)]