Skip to main content

duat_core/buffer/
opts.rs

1//! Option definitions for the [`Buffer`] widget
2//!
3//! These options are defined here, but their actual implementation is
4//! left as an exercise to plugins. This is because I want them to be
5//! configurable, and if my implementation of them clashes with some
6//! plugin, I want that plugin to be able to replace it with a more
7//! compatible version.
8//!
9//! The default implementation of these options is defined in the
10//! `duat-base` crate.
11//!
12//! [`Buffer`]: super::Buffer
13
14use crate::opts::{PrintOpts, ScrollOff};
15
16/// The default suite of options available to [`Buffer`]s
17///
18/// Unlike most other widget options, these ones are dynamic, that is,
19/// if they are changed while duat is still open, the `Buffer` will be
20/// updated accordingly.
21///
22/// # Note
23///
24/// While these options are defined as a core part of the `Buffer`,
25/// they are not implemented natively. The implementation is done in
26/// the `duat-base` crate, which means you may replace the
27/// implementation with your own version if that suits you.
28///
29/// [`Buffer`]: super::Buffer
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
31pub struct BufferOpts {
32    /// Highlights the current line
33    ///
34    /// The default is `true`
35    ///
36    /// This makes use of the `current_line` [`Form`]
37    ///
38    /// [`Form`]: crate::form::Form
39    pub highlight_current_line: bool,
40    /// Enables wrapping of lines
41    ///
42    /// The default is `true`
43    pub wrap_lines: bool,
44    /// Wrap on word boundaries, rather than on any character
45    ///
46    /// The default is `false`.
47    pub wrap_on_word: bool,
48    /// Where to start wrapping
49    ///
50    /// The default is `None`
51    ///
52    /// If this value is `None` and `opts.wrap_lines == true`, then
53    /// wrapping will take place at the right edge of the screen.
54    ///
55    /// Otherwise, if it is `Some({cap})`, then wrapping will take
56    /// place `{cap}` cells from the left edge. This value may or may
57    /// not be greater than the width of the area. If it is greater
58    /// than it, then wrapping will take place slightly outside the
59    /// screen as a concequence.
60    pub wrapping_cap: Option<u32>,
61    /// Whether to indent wrapped lines or not
62    ///
63    /// The default is `true`.
64    ///
65    /// This turns this:
66    ///
67    /// ```text
68    ///     This is a very long line of text, so long that it
69    /// wraps around
70    /// ```
71    ///
72    /// Into this:
73    ///
74    /// ```text
75    ///     This is a very long line of text, so long that it
76    ///     wraps around
77    /// ```
78    pub indent_wraps: bool,
79    /// How much space a tab should occupy
80    ///
81    /// The default is `4`
82    ///
83    /// This also affect other things, like if your tabs are converted
84    /// into spaces, this will also set how many spaces should be
85    /// added.
86    pub tabstop: u8,
87    /// How much space to keep between the cursor and edges
88    ///
89    /// The default is `ScrollOff { x: 3, y: 3 }`
90    pub scrolloff: ScrollOff,
91    /// Whether to limit scrolloff at the end of lines
92    ///
93    /// The default is `false`
94    ///
95    /// This makes it so, as you reach the end of a long line of text,
96    /// the cursor line will continue scrolling to the left,
97    /// maintaining the `scrolloff.x`'s gap.
98    pub force_scrolloff: bool,
99    /// Extra characters to be considered part of a word
100    ///
101    /// The default is `&[]`.
102    ///
103    /// Normally, word characters include all of those in the [`\w`]
104    /// character set, which most importantly includes `[0-9A-Za-z_]`.
105    ///
106    /// You can use this setting to add more characters to that list,
107    /// usually something like `-`, `$` or `@`, which are useful to
108    /// consider as word characters in some circumstances.
109    ///
110    /// [`\w`]: https://www.unicode.org/reports/tr18/#word
111    pub extra_word_chars: &'static [char],
112    /// Indent string
113    ///
114    /// The default is `Some("│")`.
115    ///
116    /// The indent lines will be printed with the `replace.indent`
117    /// [`Form`].
118    ///
119    /// A string to replace the indentation at the start of the line.
120    /// This string will repeat on every `opts.tabstop` initial spaces
121    /// or on every `\t` character, replacing that many characters of
122    /// the tab stop with those of the string.
123    ///
124    /// For example, if `tabstop == 2 && indent_str == Some("│   ")`,
125    /// this:
126    ///
127    /// ```txt
128    /// int (int var1, int var2) {
129    ///   if (var1 > 2)
130    ///     return 42;
131    ///   else
132    ///     if (var1 <= 50)
133    ///       return 20;
134    ///     else
135    ///       return 10;
136    /// }
137    /// ```
138    ///
139    /// Would be displayed like this:
140    ///
141    /// ```txt
142    /// int (int var1, int var2) {
143    /// │ if (var1 > 2)
144    /// │ │ return 42;
145    /// │ else
146    /// │ │ if (var1 <= 50)
147    /// │ │ │ return 20;
148    /// │ │ else
149    /// │ │ │ return 10;
150    /// }
151    /// ```
152    ///
153    /// That is, it will take `tabstop` characters and print them.
154    /// Where the `tabstop == 4`, it would use all 4 characters.
155    ///
156    /// [`Form`]: crate::form::Form
157    pub indent_str: Option<&'static str>,
158    /// Wether to copy the indentation string of `opts.indent_str` on
159    /// empty lines.
160    ///
161    /// The default is `true`
162    ///
163    /// If this is set to true, this str will be printed with the
164    /// `replace.indent.empty` form.
165    ///
166    /// This will always copy whichever line has the smallest ammount
167    /// of indentation.
168    pub indent_str_on_empty: bool,
169    /// An indent string, just like `opts.indent_str`, but only for
170    /// `\t`s
171    ///
172    /// The default is `None`
173    ///
174    /// This is useful for languages like python, where the mixup of
175    /// tabs and spaces on indentation can cause problems.
176    ///
177    /// If it is `Some`, the `str` will be shown with the
178    /// `replace.indent.tab` form. If this is `None`, then
179    /// `opts.indent_str` will be used instead.
180    pub indent_tab_str: Option<&'static str>,
181    /// A character to be printed in place of the space
182    ///
183    /// The default is `None`
184    ///
185    /// The char will be printed with the `replace.space` [`Form`].
186    ///
187    /// This character will replace only the space characters that are
188    /// not part of the indentation.
189    ///
190    /// [`Form`]: crate::form::Form
191    pub space_char: Option<char>,
192    /// A character to be printed on trailing whitespace
193    ///
194    /// The default is `None`
195    ///
196    /// This character will be printed with the
197    /// `replace.space.trailing` [`Form`]
198    ///
199    /// If it is `None`, it will be the same as `opts.space_char`.
200    ///
201    /// [`Form`]: crate::form::Form
202    pub space_char_trailing: Option<char>,
203    /// Which `char` should be printed in new lines
204    ///
205    /// The default is `' '` (space character)
206    ///
207    /// This character will be printed with the `replace.new_line`
208    /// [`Form`].
209    ///
210    /// [`Buffer`]: crate::buffer::Buffer
211    /// [`Form`]: crate::form::Form
212    pub new_line_char: char,
213    /// A character to be printed on the new line on empty strings
214    ///
215    /// The default is `None`
216    ///
217    /// This character will be printed with the
218    /// `replace.new_line.empty` [`Form`].
219    ///
220    /// If it is `None`, it will be the same as `opts.new_line_char`.
221    ///
222    /// [`Form`]: crate::form::Form
223    pub new_line_on_empty: Option<char>,
224    /// A character to be printed on trailing new lines
225    ///
226    /// The default is `None`
227    ///
228    /// This character will be printed with the
229    /// `replace.new_line.trailing` [`Form`].
230    ///
231    /// [`Form`]: crate::form::Form
232    pub new_line_trailing: Option<char>,
233}
234
235impl BufferOpts {
236    /// Gets [`PrintOpts`] from this [`BufferOpts`]
237    pub fn to_print_opts(&self) -> PrintOpts {
238        PrintOpts {
239            wrap_lines: self.wrap_lines,
240            wrap_on_word: self.wrap_on_word,
241            wrapping_cap: self.wrapping_cap,
242            indent_wraps: self.indent_wraps,
243            tabstop: self.tabstop,
244            print_new_line: true,
245            scrolloff: self.scrolloff,
246            force_scrolloff: self.force_scrolloff,
247            extra_word_chars: self.extra_word_chars,
248            show_ghosts: true,
249            allow_overscroll: true,
250        }
251    }
252}
253
254impl Default for BufferOpts {
255    fn default() -> Self {
256        Self {
257            highlight_current_line: false,
258            wrap_lines: true,
259            wrap_on_word: false,
260            wrapping_cap: None,
261            indent_wraps: true,
262            tabstop: 4,
263            scrolloff: ScrollOff { x: 3, y: 3 },
264            force_scrolloff: false,
265            extra_word_chars: &[],
266            indent_str: Some("▎"),
267            indent_str_on_empty: true,
268            indent_tab_str: None,
269            space_char: None,
270            space_char_trailing: None,
271            new_line_char: ' ',
272            new_line_on_empty: None,
273            new_line_trailing: Some('↵'),
274        }
275    }
276}