1use std::path::PathBuf;
4
5use serde::{Deserialize, Serialize};
6
7use crate::fold::FoldStrategy;
8use crate::history::{History, Revision};
9use crate::text::Document;
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
12pub struct BufferId(pub u64);
13
14#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
15pub enum LineEnding {
16 #[default]
17 Lf,
18 CrLf,
19 Cr,
20}
21
22#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
25pub struct FileMeta {
26 pub path: Option<PathBuf>,
27 pub encoding: String,
29 pub bom: bool,
30 pub line_ending: LineEnding,
31 pub mixed_line_endings: bool,
32}
33
34impl Default for FileMeta {
35 fn default() -> Self {
36 Self {
37 path: None,
38 encoding: "UTF-8".to_owned(),
39 bom: false,
40 line_ending: LineEnding::default(),
41 mixed_line_endings: false,
42 }
43 }
44}
45
46#[derive(Clone, Copy, Debug, PartialEq, Eq)]
51pub struct LineEdit {
52 pub start: usize,
53 pub old_end: usize,
54 pub new_end: usize,
55}
56
57impl LineEdit {
58 pub fn everything_from(start: usize) -> Self {
59 Self {
60 start,
61 old_end: usize::MAX,
62 new_end: usize::MAX,
63 }
64 }
65
66 pub fn is_everything(&self) -> bool {
67 self.old_end == usize::MAX
68 }
69}
70
71const MAX_PENDING_LINE_EDITS: usize = 1024;
72
73#[derive(Debug)]
74pub struct Buffer {
75 id: BufferId,
76 pub(crate) doc: Document,
77 pub(crate) history: History,
78 pub(crate) revision: Revision,
79 pub(crate) next_revision: Revision,
80 saved_revision: Revision,
81 pub language: Option<String>,
82 pub fold_strategy: FoldStrategy,
84 pub read_only: bool,
86 pub meta: FileMeta,
87 line_edits: Vec<LineEdit>,
89}
90
91impl Buffer {
92 pub(crate) fn new(id: BufferId, text: &str, meta: FileMeta) -> Self {
93 Self {
94 id,
95 doc: Document::new(text),
96 history: History::default(),
97 revision: 0,
98 next_revision: 1,
99 saved_revision: 0,
100 language: None,
101 fold_strategy: FoldStrategy::Indent,
102 read_only: false,
103 meta,
104 line_edits: Vec::new(),
105 }
106 }
107
108 pub fn id(&self) -> BufferId {
109 self.id
110 }
111
112 pub fn doc(&self) -> &Document {
113 &self.doc
114 }
115
116 pub fn history(&self) -> &History {
117 &self.history
118 }
119
120 pub fn revision(&self) -> Revision {
122 self.revision
123 }
124
125 pub fn is_dirty(&self) -> bool {
126 self.revision != self.saved_revision
127 }
128
129 pub fn mark_saved(&mut self) {
131 self.mark_saved_at(self.revision);
132 }
133
134 pub fn mark_saved_at(&mut self, revision: Revision) {
137 self.saved_revision = revision;
138 self.history.break_coalescing();
139 }
140
141 pub fn mark_modified(&mut self) {
144 self.saved_revision = Revision::MAX;
146 }
147
148 pub fn take_line_edits(&mut self) -> Vec<LineEdit> {
151 std::mem::take(&mut self.line_edits)
152 }
153
154 pub(crate) fn record_line_edit(&mut self, edit: LineEdit) {
155 if let Some(last) = self.line_edits.last_mut()
156 && last.old_end == usize::MAX
157 {
158 last.start = last.start.min(edit.start);
159 return;
160 }
161 if self.line_edits.len() >= MAX_PENDING_LINE_EDITS {
162 let start = self
165 .line_edits
166 .iter()
167 .map(|e| e.start)
168 .fold(edit.start, usize::min);
169 self.line_edits = vec![LineEdit::everything_from(start)];
170 return;
171 }
172 self.line_edits.push(edit);
173 }
174}