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