Add line ending selector (#35392)
Partially addresses this issue #5294 Adds a selector between `LF` and `CRLF` for the buffer's line endings, the checkmark denotes the currently selected line ending. Selector <img width="487" height="66" alt="image" src="https://github.com/user-attachments/assets/13f2480f-4d2d-4afe-adf5-385aeb421393" /> Release Notes: - Added line ending selector. --------- Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
co-authored by
Conrad Irwin
parent
638320b21e
commit
b3405c3bd1
@@ -284,6 +284,14 @@ pub enum Operation {
|
||||
/// The language server ID.
|
||||
server_id: LanguageServerId,
|
||||
},
|
||||
|
||||
/// An update to the line ending type of this buffer.
|
||||
UpdateLineEnding {
|
||||
/// The line ending type.
|
||||
line_ending: LineEnding,
|
||||
/// The buffer's lamport timestamp.
|
||||
lamport_timestamp: clock::Lamport,
|
||||
},
|
||||
}
|
||||
|
||||
/// An event that occurs in a buffer.
|
||||
@@ -1240,6 +1248,21 @@ impl Buffer {
|
||||
self.syntax_map.lock().language_registry()
|
||||
}
|
||||
|
||||
/// Assign the line ending type to the buffer.
|
||||
pub fn set_line_ending(&mut self, line_ending: LineEnding, cx: &mut Context<Self>) {
|
||||
self.text.set_line_ending(line_ending);
|
||||
|
||||
let lamport_timestamp = self.text.lamport_clock.tick();
|
||||
self.send_operation(
|
||||
Operation::UpdateLineEnding {
|
||||
line_ending,
|
||||
lamport_timestamp,
|
||||
},
|
||||
true,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
|
||||
/// Assign the buffer a new [`Capability`].
|
||||
pub fn set_capability(&mut self, capability: Capability, cx: &mut Context<Self>) {
|
||||
if self.capability != capability {
|
||||
@@ -2557,7 +2580,7 @@ impl Buffer {
|
||||
Operation::UpdateSelections { selections, .. } => selections
|
||||
.iter()
|
||||
.all(|s| self.can_resolve(&s.start) && self.can_resolve(&s.end)),
|
||||
Operation::UpdateCompletionTriggers { .. } => true,
|
||||
Operation::UpdateCompletionTriggers { .. } | Operation::UpdateLineEnding { .. } => true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2623,6 +2646,13 @@ impl Buffer {
|
||||
}
|
||||
self.text.lamport_clock.observe(lamport_timestamp);
|
||||
}
|
||||
Operation::UpdateLineEnding {
|
||||
line_ending,
|
||||
lamport_timestamp,
|
||||
} => {
|
||||
self.text.set_line_ending(line_ending);
|
||||
self.text.lamport_clock.observe(lamport_timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4814,6 +4844,9 @@ impl operation_queue::Operation for Operation {
|
||||
}
|
||||
| Operation::UpdateCompletionTriggers {
|
||||
lamport_timestamp, ..
|
||||
}
|
||||
| Operation::UpdateLineEnding {
|
||||
lamport_timestamp, ..
|
||||
} => *lamport_timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,78 @@ fn test_line_endings(cx: &mut gpui::App) {
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_set_line_ending(cx: &mut TestAppContext) {
|
||||
let base = cx.new(|cx| Buffer::local("one\ntwo\nthree\n", cx));
|
||||
let base_replica = cx.new(|cx| {
|
||||
Buffer::from_proto(1, Capability::ReadWrite, base.read(cx).to_proto(cx), None).unwrap()
|
||||
});
|
||||
base.update(cx, |_buffer, cx| {
|
||||
cx.subscribe(&base_replica, |this, _, event, cx| {
|
||||
if let BufferEvent::Operation {
|
||||
operation,
|
||||
is_local: true,
|
||||
} = event
|
||||
{
|
||||
this.apply_ops([operation.clone()], cx);
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
});
|
||||
base_replica.update(cx, |_buffer, cx| {
|
||||
cx.subscribe(&base, |this, _, event, cx| {
|
||||
if let BufferEvent::Operation {
|
||||
operation,
|
||||
is_local: true,
|
||||
} = event
|
||||
{
|
||||
this.apply_ops([operation.clone()], cx);
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
});
|
||||
|
||||
// Base
|
||||
base_replica.read_with(cx, |buffer, _| {
|
||||
assert_eq!(buffer.line_ending(), LineEnding::Unix);
|
||||
});
|
||||
base.update(cx, |buffer, cx| {
|
||||
assert_eq!(buffer.line_ending(), LineEnding::Unix);
|
||||
buffer.set_line_ending(LineEnding::Windows, cx);
|
||||
assert_eq!(buffer.line_ending(), LineEnding::Windows);
|
||||
});
|
||||
base_replica.read_with(cx, |buffer, _| {
|
||||
assert_eq!(buffer.line_ending(), LineEnding::Windows);
|
||||
});
|
||||
base.update(cx, |buffer, cx| {
|
||||
buffer.set_line_ending(LineEnding::Unix, cx);
|
||||
assert_eq!(buffer.line_ending(), LineEnding::Unix);
|
||||
});
|
||||
base_replica.read_with(cx, |buffer, _| {
|
||||
assert_eq!(buffer.line_ending(), LineEnding::Unix);
|
||||
});
|
||||
|
||||
// Replica
|
||||
base.read_with(cx, |buffer, _| {
|
||||
assert_eq!(buffer.line_ending(), LineEnding::Unix);
|
||||
});
|
||||
base_replica.update(cx, |buffer, cx| {
|
||||
assert_eq!(buffer.line_ending(), LineEnding::Unix);
|
||||
buffer.set_line_ending(LineEnding::Windows, cx);
|
||||
assert_eq!(buffer.line_ending(), LineEnding::Windows);
|
||||
});
|
||||
base.read_with(cx, |buffer, _| {
|
||||
assert_eq!(buffer.line_ending(), LineEnding::Windows);
|
||||
});
|
||||
base_replica.update(cx, |buffer, cx| {
|
||||
buffer.set_line_ending(LineEnding::Unix, cx);
|
||||
assert_eq!(buffer.line_ending(), LineEnding::Unix);
|
||||
});
|
||||
base.read_with(cx, |buffer, _| {
|
||||
assert_eq!(buffer.line_ending(), LineEnding::Unix);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_select_language(cx: &mut App) {
|
||||
init_settings(cx, |_| {});
|
||||
|
||||
@@ -90,6 +90,15 @@ pub fn serialize_operation(operation: &crate::Operation) -> proto::Operation {
|
||||
language_server_id: server_id.to_proto(),
|
||||
},
|
||||
),
|
||||
|
||||
crate::Operation::UpdateLineEnding {
|
||||
line_ending,
|
||||
lamport_timestamp,
|
||||
} => proto::operation::Variant::UpdateLineEnding(proto::operation::UpdateLineEnding {
|
||||
replica_id: lamport_timestamp.replica_id as u32,
|
||||
lamport_timestamp: lamport_timestamp.value,
|
||||
line_ending: serialize_line_ending(*line_ending) as i32,
|
||||
}),
|
||||
}),
|
||||
}
|
||||
}
|
||||
@@ -341,6 +350,18 @@ pub fn deserialize_operation(message: proto::Operation) -> Result<crate::Operati
|
||||
server_id: LanguageServerId::from_proto(message.language_server_id),
|
||||
}
|
||||
}
|
||||
proto::operation::Variant::UpdateLineEnding(message) => {
|
||||
crate::Operation::UpdateLineEnding {
|
||||
lamport_timestamp: clock::Lamport {
|
||||
replica_id: message.replica_id as ReplicaId,
|
||||
value: message.lamport_timestamp,
|
||||
},
|
||||
line_ending: deserialize_line_ending(
|
||||
proto::LineEnding::from_i32(message.line_ending)
|
||||
.context("missing line_ending")?,
|
||||
),
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -496,6 +517,10 @@ pub fn lamport_timestamp_for_operation(operation: &proto::Operation) -> Option<c
|
||||
replica_id = op.replica_id;
|
||||
value = op.lamport_timestamp;
|
||||
}
|
||||
proto::operation::Variant::UpdateLineEnding(op) => {
|
||||
replica_id = op.replica_id;
|
||||
value = op.lamport_timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
Some(clock::Lamport {
|
||||
|
||||
Reference in New Issue
Block a user