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}