1use std::{fmt::Display, ops::Deref};
5
6use crossterm::event::KeyModifiers;
7use xdg::BaseDirectories;
8
9pub mod app;
10pub mod config;
11pub mod storage;
12
13pub fn base_dirs() -> Result<BaseDirectories, xdg::BaseDirectoriesError> {
15 BaseDirectories::with_prefix("mantra")
16}
17
18pub fn value_from_modifiers(modifiers: KeyModifiers) -> i32 {
20 let mut value = 10;
21 if modifiers.contains(KeyModifiers::SHIFT) {
22 value = 1;
23 }
24 if modifiers.contains(KeyModifiers::CONTROL) {
25 value *= 5;
26 }
27 if modifiers.contains(KeyModifiers::ALT) {
28 value *= 20;
29 }
30
31 value
32}
33
34#[derive(Default)]
37pub struct CursoredString {
38 buf: String,
39 index: usize,
40 pub inserting: bool,
41}
42
43impl CursoredString {
44 pub fn new() -> Self {
46 Self::default()
47 }
48
49 pub fn as_str(&self) -> &str {
51 self
52 }
53
54 pub fn cursor_index(&self) -> usize {
56 self.index
57 }
58
59 pub fn next(&mut self) {
61 self.index = self.index.saturating_add(1).clamp(0, self.buf.len())
62 }
63
64 pub fn prev(&mut self) {
66 self.index = self.index.saturating_sub(1).clamp(0, self.buf.len())
67 }
68
69 pub fn remove_behind(&mut self) {
71 if self.index > 0 {
73 let old_len = self.buf.len();
74 let mut index = 0;
75 self.buf.retain(|_| {
77 index += 1;
78 index != self.index
79 });
80 if self.buf.len() < old_len {
82 self.index -= 1;
83 };
84 }
85 }
86
87 pub fn remove_ahead(&mut self) {
89 if self.index < self.buf.chars().count() {
90 let mut index = 0;
91 self.buf.retain(|_| {
92 index += 1;
93 if index - 1 == self.index {
94 return false;
95 }
96 true
97 })
98 }
99 }
100
101 pub fn insert(&mut self, value: char) {
104 if self.inserting {
105 self.remove_ahead();
106 }
107 let byte_index = self
109 .buf
110 .char_indices()
111 .map(|(i, _)| i)
112 .nth(self.index)
113 .unwrap_or(self.buf.len());
114
115 self.buf.insert(byte_index, value);
116 self.index += 1
117 }
118}
119
120impl Display for CursoredString {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 self.buf.fmt(f)
123 }
124}
125
126impl From<CursoredString> for String {
127 fn from(value: CursoredString) -> Self {
128 value.buf
129 }
130}
131
132impl Deref for CursoredString {
133 type Target = str;
134
135 fn deref(&self) -> &Self::Target {
136 self.buf.as_str()
137 }
138}
139
140impl From<String> for CursoredString {
141 fn from(value: String) -> Self {
142 Self {
143 buf: value,
144 index: 0,
145 inserting: false,
146 }
147 }
148}