Merge branch 'main' into autoindent-on-paste
This commit is contained in:
commit
3a74290359
17 changed files with 212 additions and 91 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -6994,7 +6994,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed"
|
name = "zed"
|
||||||
version = "0.49.0"
|
version = "0.49.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"activity_indicator",
|
"activity_indicator",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
|
|
@ -14,30 +14,30 @@
|
||||||
"k": "vim::Up",
|
"k": "vim::Up",
|
||||||
"l": "vim::Right",
|
"l": "vim::Right",
|
||||||
"0": "vim::StartOfLine",
|
"0": "vim::StartOfLine",
|
||||||
"shift-$": "vim::EndOfLine",
|
"$": "vim::EndOfLine",
|
||||||
"shift-G": "vim::EndOfDocument",
|
"shift-g": "vim::EndOfDocument",
|
||||||
"w": "vim::NextWordStart",
|
"w": "vim::NextWordStart",
|
||||||
"shift-W": [
|
"shift-w": [
|
||||||
"vim::NextWordStart",
|
"vim::NextWordStart",
|
||||||
{
|
{
|
||||||
"ignorePunctuation": true
|
"ignorePunctuation": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"e": "vim::NextWordEnd",
|
"e": "vim::NextWordEnd",
|
||||||
"shift-E": [
|
"shift-e": [
|
||||||
"vim::NextWordEnd",
|
"vim::NextWordEnd",
|
||||||
{
|
{
|
||||||
"ignorePunctuation": true
|
"ignorePunctuation": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"b": "vim::PreviousWordStart",
|
"b": "vim::PreviousWordStart",
|
||||||
"shift-B": [
|
"shift-b": [
|
||||||
"vim::PreviousWordStart",
|
"vim::PreviousWordStart",
|
||||||
{
|
{
|
||||||
"ignorePunctuation": true
|
"ignorePunctuation": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"shift-%": "vim::Matching",
|
"%": "vim::Matching",
|
||||||
"escape": "editor::Cancel"
|
"escape": "editor::Cancel"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -48,12 +48,12 @@
|
||||||
"vim::PushOperator",
|
"vim::PushOperator",
|
||||||
"Change"
|
"Change"
|
||||||
],
|
],
|
||||||
"shift-C": "vim::ChangeToEndOfLine",
|
"shift-c": "vim::ChangeToEndOfLine",
|
||||||
"d": [
|
"d": [
|
||||||
"vim::PushOperator",
|
"vim::PushOperator",
|
||||||
"Delete"
|
"Delete"
|
||||||
],
|
],
|
||||||
"shift-D": "vim::DeleteToEndOfLine",
|
"shift-d": "vim::DeleteToEndOfLine",
|
||||||
"y": [
|
"y": [
|
||||||
"vim::PushOperator",
|
"vim::PushOperator",
|
||||||
"Yank"
|
"Yank"
|
||||||
|
@ -62,14 +62,14 @@
|
||||||
"vim::SwitchMode",
|
"vim::SwitchMode",
|
||||||
"Insert"
|
"Insert"
|
||||||
],
|
],
|
||||||
"shift-I": "vim::InsertFirstNonWhitespace",
|
"shift-i": "vim::InsertFirstNonWhitespace",
|
||||||
"a": "vim::InsertAfter",
|
"a": "vim::InsertAfter",
|
||||||
"shift-A": "vim::InsertEndOfLine",
|
"shift-a": "vim::InsertEndOfLine",
|
||||||
"x": "vim::DeleteRight",
|
"x": "vim::DeleteRight",
|
||||||
"shift-X": "vim::DeleteLeft",
|
"shift-x": "vim::DeleteLeft",
|
||||||
"shift-^": "vim::FirstNonWhitespace",
|
"^": "vim::FirstNonWhitespace",
|
||||||
"o": "vim::InsertLineBelow",
|
"o": "vim::InsertLineBelow",
|
||||||
"shift-O": "vim::InsertLineAbove",
|
"shift-o": "vim::InsertLineAbove",
|
||||||
"v": [
|
"v": [
|
||||||
"vim::SwitchMode",
|
"vim::SwitchMode",
|
||||||
{
|
{
|
||||||
|
@ -78,7 +78,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"shift-V": [
|
"shift-v": [
|
||||||
"vim::SwitchMode",
|
"vim::SwitchMode",
|
||||||
{
|
{
|
||||||
"Visual": {
|
"Visual": {
|
||||||
|
@ -113,7 +113,7 @@
|
||||||
"context": "Editor && vim_operator == c",
|
"context": "Editor && vim_operator == c",
|
||||||
"bindings": {
|
"bindings": {
|
||||||
"w": "vim::ChangeWord",
|
"w": "vim::ChangeWord",
|
||||||
"shift-W": [
|
"shift-w": [
|
||||||
"vim::ChangeWord",
|
"vim::ChangeWord",
|
||||||
{
|
{
|
||||||
"ignorePunctuation": true
|
"ignorePunctuation": true
|
||||||
|
|
|
@ -41,6 +41,7 @@ pub struct Keystroke {
|
||||||
pub alt: bool,
|
pub alt: bool,
|
||||||
pub shift: bool,
|
pub shift: bool,
|
||||||
pub cmd: bool,
|
pub cmd: bool,
|
||||||
|
pub function: bool,
|
||||||
pub key: String,
|
pub key: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,6 +278,7 @@ impl Keystroke {
|
||||||
let mut alt = false;
|
let mut alt = false;
|
||||||
let mut shift = false;
|
let mut shift = false;
|
||||||
let mut cmd = false;
|
let mut cmd = false;
|
||||||
|
let mut function = false;
|
||||||
let mut key = None;
|
let mut key = None;
|
||||||
|
|
||||||
let mut components = source.split("-").peekable();
|
let mut components = source.split("-").peekable();
|
||||||
|
@ -286,6 +288,7 @@ impl Keystroke {
|
||||||
"alt" => alt = true,
|
"alt" => alt = true,
|
||||||
"shift" => shift = true,
|
"shift" => shift = true,
|
||||||
"cmd" => cmd = true,
|
"cmd" => cmd = true,
|
||||||
|
"fn" => function = true,
|
||||||
_ => {
|
_ => {
|
||||||
if let Some(component) = components.peek() {
|
if let Some(component) = components.peek() {
|
||||||
if component.is_empty() && source.ends_with('-') {
|
if component.is_empty() && source.ends_with('-') {
|
||||||
|
@ -306,6 +309,7 @@ impl Keystroke {
|
||||||
alt,
|
alt,
|
||||||
shift,
|
shift,
|
||||||
cmd,
|
cmd,
|
||||||
|
function,
|
||||||
key: key.unwrap(),
|
key: key.unwrap(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -464,6 +468,7 @@ mod tests {
|
||||||
alt: false,
|
alt: false,
|
||||||
shift: false,
|
shift: false,
|
||||||
cmd: false,
|
cmd: false,
|
||||||
|
function: false,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -475,6 +480,7 @@ mod tests {
|
||||||
alt: true,
|
alt: true,
|
||||||
shift: true,
|
shift: true,
|
||||||
cmd: false,
|
cmd: false,
|
||||||
|
function: false,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -486,6 +492,7 @@ mod tests {
|
||||||
alt: false,
|
alt: false,
|
||||||
shift: true,
|
shift: true,
|
||||||
cmd: true,
|
cmd: true,
|
||||||
|
function: false,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -210,19 +210,24 @@ impl Event {
|
||||||
unsafe fn parse_keystroke(native_event: id) -> Keystroke {
|
unsafe fn parse_keystroke(native_event: id) -> Keystroke {
|
||||||
use cocoa::appkit::*;
|
use cocoa::appkit::*;
|
||||||
|
|
||||||
let modifiers = native_event.modifierFlags();
|
|
||||||
let ctrl = modifiers.contains(NSEventModifierFlags::NSControlKeyMask);
|
|
||||||
let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask);
|
|
||||||
let mut shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask);
|
|
||||||
let cmd = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask);
|
|
||||||
|
|
||||||
let mut chars_ignoring_modifiers =
|
let mut chars_ignoring_modifiers =
|
||||||
CStr::from_ptr(native_event.charactersIgnoringModifiers().UTF8String() as *mut c_char)
|
CStr::from_ptr(native_event.charactersIgnoringModifiers().UTF8String() as *mut c_char)
|
||||||
.to_str()
|
.to_str()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let first_char = chars_ignoring_modifiers.chars().next().map(|ch| ch as u16);
|
||||||
|
let modifiers = native_event.modifierFlags();
|
||||||
|
|
||||||
|
let ctrl = modifiers.contains(NSEventModifierFlags::NSControlKeyMask);
|
||||||
|
let alt = modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask);
|
||||||
|
let mut shift = modifiers.contains(NSEventModifierFlags::NSShiftKeyMask);
|
||||||
|
let cmd = modifiers.contains(NSEventModifierFlags::NSCommandKeyMask);
|
||||||
|
let function = modifiers.contains(NSEventModifierFlags::NSFunctionKeyMask)
|
||||||
|
&& first_char.map_or(true, |ch| {
|
||||||
|
ch < NSUpArrowFunctionKey || ch > NSModeSwitchFunctionKey
|
||||||
|
});
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
let key = match chars_ignoring_modifiers.chars().next().map(|ch| ch as u16) {
|
let key = match first_char {
|
||||||
Some(SPACE_KEY) => "space",
|
Some(SPACE_KEY) => "space",
|
||||||
Some(BACKSPACE_KEY) => "backspace",
|
Some(BACKSPACE_KEY) => "backspace",
|
||||||
Some(ENTER_KEY) | Some(NUMPAD_ENTER_KEY) => "enter",
|
Some(ENTER_KEY) | Some(NUMPAD_ENTER_KEY) => "enter",
|
||||||
|
@ -282,6 +287,7 @@ unsafe fn parse_keystroke(native_event: id) -> Keystroke {
|
||||||
alt,
|
alt,
|
||||||
shift,
|
shift,
|
||||||
cmd,
|
cmd,
|
||||||
|
function,
|
||||||
key: key.into(),
|
key: key.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,6 +184,7 @@ impl MacForegroundPlatform {
|
||||||
(keystroke.cmd, NSEventModifierFlags::NSCommandKeyMask),
|
(keystroke.cmd, NSEventModifierFlags::NSCommandKeyMask),
|
||||||
(keystroke.ctrl, NSEventModifierFlags::NSControlKeyMask),
|
(keystroke.ctrl, NSEventModifierFlags::NSControlKeyMask),
|
||||||
(keystroke.alt, NSEventModifierFlags::NSAlternateKeyMask),
|
(keystroke.alt, NSEventModifierFlags::NSAlternateKeyMask),
|
||||||
|
(keystroke.shift, NSEventModifierFlags::NSShiftKeyMask),
|
||||||
] {
|
] {
|
||||||
if *modifier {
|
if *modifier {
|
||||||
mask |= *flag;
|
mask |= *flag;
|
||||||
|
|
|
@ -154,6 +154,10 @@ unsafe fn build_classes() {
|
||||||
sel!(performKeyEquivalent:),
|
sel!(performKeyEquivalent:),
|
||||||
handle_key_equivalent as extern "C" fn(&Object, Sel, id) -> BOOL,
|
handle_key_equivalent as extern "C" fn(&Object, Sel, id) -> BOOL,
|
||||||
);
|
);
|
||||||
|
decl.add_method(
|
||||||
|
sel!(keyDown:),
|
||||||
|
handle_key_down as extern "C" fn(&Object, Sel, id),
|
||||||
|
);
|
||||||
decl.add_method(
|
decl.add_method(
|
||||||
sel!(mouseDown:),
|
sel!(mouseDown:),
|
||||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||||
|
@ -275,7 +279,8 @@ struct WindowState {
|
||||||
should_close_callback: Option<Box<dyn FnMut() -> bool>>,
|
should_close_callback: Option<Box<dyn FnMut() -> bool>>,
|
||||||
close_callback: Option<Box<dyn FnOnce()>>,
|
close_callback: Option<Box<dyn FnOnce()>>,
|
||||||
input_handler: Option<Box<dyn InputHandler>>,
|
input_handler: Option<Box<dyn InputHandler>>,
|
||||||
pending_key_down_event: Option<KeyDownEvent>,
|
pending_key_down: Option<(KeyDownEvent, Option<InsertText>)>,
|
||||||
|
performed_key_equivalent: bool,
|
||||||
synthetic_drag_counter: usize,
|
synthetic_drag_counter: usize,
|
||||||
executor: Rc<executor::Foreground>,
|
executor: Rc<executor::Foreground>,
|
||||||
scene_to_render: Option<Scene>,
|
scene_to_render: Option<Scene>,
|
||||||
|
@ -287,6 +292,11 @@ struct WindowState {
|
||||||
previous_modifiers_changed_event: Option<Event>,
|
previous_modifiers_changed_event: Option<Event>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct InsertText {
|
||||||
|
replacement_range: Option<Range<usize>>,
|
||||||
|
text: String,
|
||||||
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn open(
|
pub fn open(
|
||||||
id: usize,
|
id: usize,
|
||||||
|
@ -359,7 +369,8 @@ impl Window {
|
||||||
close_callback: None,
|
close_callback: None,
|
||||||
activate_callback: None,
|
activate_callback: None,
|
||||||
input_handler: None,
|
input_handler: None,
|
||||||
pending_key_down_event: None,
|
pending_key_down: None,
|
||||||
|
performed_key_equivalent: false,
|
||||||
synthetic_drag_counter: 0,
|
synthetic_drag_counter: 0,
|
||||||
executor,
|
executor,
|
||||||
scene_to_render: Default::default(),
|
scene_to_render: Default::default(),
|
||||||
|
@ -689,13 +700,28 @@ extern "C" fn dealloc_view(this: &Object, _: Sel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn handle_key_equivalent(this: &Object, _: Sel, native_event: id) -> BOOL {
|
extern "C" fn handle_key_equivalent(this: &Object, _: Sel, native_event: id) -> BOOL {
|
||||||
|
handle_key_event(this, native_event, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn handle_key_down(this: &Object, _: Sel, native_event: id) {
|
||||||
|
handle_key_event(this, native_event, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent: bool) -> BOOL {
|
||||||
let window_state = unsafe { get_window_state(this) };
|
let window_state = unsafe { get_window_state(this) };
|
||||||
|
|
||||||
let mut window_state_borrow = window_state.as_ref().borrow_mut();
|
let mut window_state_borrow = window_state.as_ref().borrow_mut();
|
||||||
|
|
||||||
let event = unsafe { Event::from_native(native_event, Some(window_state_borrow.size().y())) };
|
let event = unsafe { Event::from_native(native_event, Some(window_state_borrow.size().y())) };
|
||||||
if let Some(event) = event {
|
if let Some(event) = event {
|
||||||
window_state_borrow.pending_key_down_event = match event {
|
if key_equivalent {
|
||||||
|
window_state_borrow.performed_key_equivalent = true;
|
||||||
|
} else if window_state_borrow.performed_key_equivalent {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
let function_is_held;
|
||||||
|
window_state_borrow.pending_key_down = match event {
|
||||||
Event::KeyDown(event) => {
|
Event::KeyDown(event) => {
|
||||||
let keydown = event.keystroke.clone();
|
let keydown = event.keystroke.clone();
|
||||||
// Ignore events from held-down keys after some of the initially-pressed keys
|
// Ignore events from held-down keys after some of the initially-pressed keys
|
||||||
|
@ -708,19 +734,23 @@ extern "C" fn handle_key_equivalent(this: &Object, _: Sel, native_event: id) ->
|
||||||
window_state_borrow.last_fresh_keydown = Some(keydown);
|
window_state_borrow.last_fresh_keydown = Some(keydown);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(event)
|
function_is_held = event.keystroke.function;
|
||||||
|
Some((event, None))
|
||||||
}
|
}
|
||||||
_ => return NO,
|
_ => return NO,
|
||||||
};
|
};
|
||||||
drop(window_state_borrow);
|
drop(window_state_borrow);
|
||||||
|
|
||||||
unsafe {
|
if !function_is_held {
|
||||||
let input_context: id = msg_send![this, inputContext];
|
unsafe {
|
||||||
let _: BOOL = msg_send![input_context, handleEvent: native_event];
|
let input_context: id = msg_send![this, inputContext];
|
||||||
|
let _: BOOL = msg_send![input_context, handleEvent: native_event];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut handled = false;
|
||||||
let mut window_state_borrow = window_state.borrow_mut();
|
let mut window_state_borrow = window_state.borrow_mut();
|
||||||
if let Some(event) = window_state_borrow.pending_key_down_event.take() {
|
if let Some((event, insert_text)) = window_state_borrow.pending_key_down.take() {
|
||||||
if let Some(mut callback) = window_state_borrow.event_callback.take() {
|
if let Some(mut callback) = window_state_borrow.event_callback.take() {
|
||||||
drop(window_state_borrow);
|
drop(window_state_borrow);
|
||||||
|
|
||||||
|
@ -729,14 +759,26 @@ extern "C" fn handle_key_equivalent(this: &Object, _: Sel, native_event: id) ->
|
||||||
.flatten()
|
.flatten()
|
||||||
.is_some();
|
.is_some();
|
||||||
if !is_composing {
|
if !is_composing {
|
||||||
callback(Event::KeyDown(event));
|
handled = callback(Event::KeyDown(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !handled {
|
||||||
|
if let Some(insert) = insert_text {
|
||||||
|
handled = true;
|
||||||
|
with_input_handler(this, |input_handler| {
|
||||||
|
input_handler
|
||||||
|
.replace_text_in_range(insert.replacement_range, &insert.text)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window_state.borrow_mut().event_callback = Some(callback);
|
window_state.borrow_mut().event_callback = Some(callback);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
YES
|
handled as BOOL
|
||||||
} else {
|
} else {
|
||||||
NO
|
NO
|
||||||
}
|
}
|
||||||
|
@ -819,6 +861,7 @@ extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) {
|
||||||
ctrl: false,
|
ctrl: false,
|
||||||
alt: false,
|
alt: false,
|
||||||
shift: false,
|
shift: false,
|
||||||
|
function: false,
|
||||||
key: ".".into(),
|
key: ".".into(),
|
||||||
};
|
};
|
||||||
let event = Event::KeyDown(KeyDownEvent {
|
let event = Event::KeyDown(KeyDownEvent {
|
||||||
|
@ -837,6 +880,7 @@ extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) {
|
||||||
extern "C" fn send_event(this: &Object, _: Sel, native_event: id) {
|
extern "C" fn send_event(this: &Object, _: Sel, native_event: id) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let () = msg_send![super(this, class!(NSWindow)), sendEvent: native_event];
|
let () = msg_send![super(this, class!(NSWindow)), sendEvent: native_event];
|
||||||
|
get_window_state(this).borrow_mut().performed_key_equivalent = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1042,7 +1086,7 @@ extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NS
|
||||||
unsafe {
|
unsafe {
|
||||||
let window_state = get_window_state(this);
|
let window_state = get_window_state(this);
|
||||||
let mut window_state_borrow = window_state.borrow_mut();
|
let mut window_state_borrow = window_state.borrow_mut();
|
||||||
let pending_key_down_event = window_state_borrow.pending_key_down_event.take();
|
let pending_key_down = window_state_borrow.pending_key_down.take();
|
||||||
drop(window_state_borrow);
|
drop(window_state_borrow);
|
||||||
|
|
||||||
let is_attributed_string: BOOL =
|
let is_attributed_string: BOOL =
|
||||||
|
@ -1062,24 +1106,17 @@ extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NS
|
||||||
.flatten()
|
.flatten()
|
||||||
.is_some();
|
.is_some();
|
||||||
|
|
||||||
if is_composing || text.chars().count() > 1 || pending_key_down_event.is_none() {
|
if is_composing || text.chars().count() > 1 || pending_key_down.is_none() {
|
||||||
with_input_handler(this, |input_handler| {
|
with_input_handler(this, |input_handler| {
|
||||||
input_handler.replace_text_in_range(replacement_range, text)
|
input_handler.replace_text_in_range(replacement_range, text)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let mut handled = false;
|
let mut pending_key_down = pending_key_down.unwrap();
|
||||||
|
pending_key_down.1 = Some(InsertText {
|
||||||
let event_callback = window_state.borrow_mut().event_callback.take();
|
replacement_range,
|
||||||
if let Some(mut event_callback) = event_callback {
|
text: text.to_string(),
|
||||||
handled = event_callback(Event::KeyDown(pending_key_down_event.unwrap()));
|
});
|
||||||
window_state.borrow_mut().event_callback = Some(event_callback);
|
window_state.borrow_mut().pending_key_down = Some(pending_key_down);
|
||||||
}
|
|
||||||
|
|
||||||
if !handled {
|
|
||||||
with_input_handler(this, |input_handler| {
|
|
||||||
input_handler.replace_text_in_range(replacement_range, text)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1092,10 +1129,7 @@ extern "C" fn set_marked_text(
|
||||||
replacement_range: NSRange,
|
replacement_range: NSRange,
|
||||||
) {
|
) {
|
||||||
unsafe {
|
unsafe {
|
||||||
get_window_state(this)
|
get_window_state(this).borrow_mut().pending_key_down.take();
|
||||||
.borrow_mut()
|
|
||||||
.pending_key_down_event
|
|
||||||
.take();
|
|
||||||
|
|
||||||
let is_attributed_string: BOOL =
|
let is_attributed_string: BOOL =
|
||||||
msg_send![text, isKindOfClass: [class!(NSAttributedString)]];
|
msg_send![text, isKindOfClass: [class!(NSAttributedString)]];
|
||||||
|
|
|
@ -173,4 +173,12 @@ impl View for ConnectedView {
|
||||||
self.terminal
|
self.terminal
|
||||||
.update(cx, |terminal, _| terminal.write_to_pty(text.into()));
|
.update(cx, |terminal, _| terminal.write_to_pty(text.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn keymap_context(&self, _: &gpui::AppContext) -> gpui::keymap::Context {
|
||||||
|
let mut context = Self::default_keymap_context();
|
||||||
|
if self.modal {
|
||||||
|
context.set.insert("ModalTerminal".into());
|
||||||
|
}
|
||||||
|
context
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -311,6 +311,7 @@ mod test {
|
||||||
alt: false,
|
alt: false,
|
||||||
shift: false,
|
shift: false,
|
||||||
cmd: false,
|
cmd: false,
|
||||||
|
function: false,
|
||||||
key: "🖖🏻".to_string(), //2 char string
|
key: "🖖🏻".to_string(), //2 char string
|
||||||
};
|
};
|
||||||
assert_eq!(to_esc_str(&ks, &TermMode::NONE), None);
|
assert_eq!(to_esc_str(&ks, &TermMode::NONE), None);
|
||||||
|
|
|
@ -171,14 +171,6 @@ impl View for TerminalView {
|
||||||
cx.focus(view.content.handle());
|
cx.focus(view.content.handle());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keymap_context(&self, _: &gpui::AppContext) -> gpui::keymap::Context {
|
|
||||||
let mut context = Self::default_keymap_context();
|
|
||||||
if self.modal {
|
|
||||||
context.set.insert("ModalTerminal".into());
|
|
||||||
}
|
|
||||||
context
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl View for ErrorView {
|
impl View for ErrorView {
|
||||||
|
|
|
@ -427,7 +427,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_jump_to_line_boundaries(cx: &mut gpui::TestAppContext) {
|
async fn test_jump_to_line_boundaries(cx: &mut gpui::TestAppContext) {
|
||||||
let cx = VimTestContext::new(cx, true).await;
|
let cx = VimTestContext::new(cx, true).await;
|
||||||
let mut cx = cx.binding(["shift-$"]);
|
let mut cx = cx.binding(["$"]);
|
||||||
cx.assert("T|est test", "Test tes|t");
|
cx.assert("T|est test", "Test tes|t");
|
||||||
cx.assert("Test tes|t", "Test tes|t");
|
cx.assert("Test tes|t", "Test tes|t");
|
||||||
cx.assert(
|
cx.assert(
|
||||||
|
@ -471,7 +471,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_jump_to_end(cx: &mut gpui::TestAppContext) {
|
async fn test_jump_to_end(cx: &mut gpui::TestAppContext) {
|
||||||
let cx = VimTestContext::new(cx, true).await;
|
let cx = VimTestContext::new(cx, true).await;
|
||||||
let mut cx = cx.binding(["shift-G"]);
|
let mut cx = cx.binding(["shift-g"]);
|
||||||
|
|
||||||
cx.assert(
|
cx.assert(
|
||||||
indoc! {"
|
indoc! {"
|
||||||
|
@ -561,7 +561,7 @@ mod test {
|
||||||
);
|
);
|
||||||
|
|
||||||
for cursor_offset in cursor_offsets {
|
for cursor_offset in cursor_offsets {
|
||||||
cx.simulate_keystroke("shift-W");
|
cx.simulate_keystroke("shift-w");
|
||||||
cx.assert_editor_selections(vec![Selection::from_offset(cursor_offset)]);
|
cx.assert_editor_selections(vec![Selection::from_offset(cursor_offset)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -607,7 +607,7 @@ mod test {
|
||||||
Mode::Normal,
|
Mode::Normal,
|
||||||
);
|
);
|
||||||
for cursor_offset in cursor_offsets {
|
for cursor_offset in cursor_offsets {
|
||||||
cx.simulate_keystroke("shift-E");
|
cx.simulate_keystroke("shift-e");
|
||||||
cx.assert_editor_selections(vec![Selection::from_offset(cursor_offset)]);
|
cx.assert_editor_selections(vec![Selection::from_offset(cursor_offset)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -653,7 +653,7 @@ mod test {
|
||||||
Mode::Normal,
|
Mode::Normal,
|
||||||
);
|
);
|
||||||
for cursor_offset in cursor_offsets.into_iter().rev() {
|
for cursor_offset in cursor_offsets.into_iter().rev() {
|
||||||
cx.simulate_keystroke("shift-B");
|
cx.simulate_keystroke("shift-b");
|
||||||
cx.assert_editor_selections(vec![Selection::from_offset(cursor_offset)]);
|
cx.assert_editor_selections(vec![Selection::from_offset(cursor_offset)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -740,7 +740,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_insert_end_of_line(cx: &mut gpui::TestAppContext) {
|
async fn test_insert_end_of_line(cx: &mut gpui::TestAppContext) {
|
||||||
let cx = VimTestContext::new(cx, true).await;
|
let cx = VimTestContext::new(cx, true).await;
|
||||||
let mut cx = cx.binding(["shift-A"]).mode_after(Mode::Insert);
|
let mut cx = cx.binding(["shift-a"]).mode_after(Mode::Insert);
|
||||||
cx.assert("The q|uick", "The quick|");
|
cx.assert("The q|uick", "The quick|");
|
||||||
cx.assert("The q|uick ", "The quick |");
|
cx.assert("The q|uick ", "The quick |");
|
||||||
cx.assert("|", "|");
|
cx.assert("|", "|");
|
||||||
|
@ -765,7 +765,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_jump_to_first_non_whitespace(cx: &mut gpui::TestAppContext) {
|
async fn test_jump_to_first_non_whitespace(cx: &mut gpui::TestAppContext) {
|
||||||
let cx = VimTestContext::new(cx, true).await;
|
let cx = VimTestContext::new(cx, true).await;
|
||||||
let mut cx = cx.binding(["shift-^"]);
|
let mut cx = cx.binding(["^"]);
|
||||||
cx.assert("The q|uick", "|The quick");
|
cx.assert("The q|uick", "|The quick");
|
||||||
cx.assert(" The q|uick", " |The quick");
|
cx.assert(" The q|uick", " |The quick");
|
||||||
cx.assert("|", "|");
|
cx.assert("|", "|");
|
||||||
|
@ -792,7 +792,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_insert_first_non_whitespace(cx: &mut gpui::TestAppContext) {
|
async fn test_insert_first_non_whitespace(cx: &mut gpui::TestAppContext) {
|
||||||
let cx = VimTestContext::new(cx, true).await;
|
let cx = VimTestContext::new(cx, true).await;
|
||||||
let mut cx = cx.binding(["shift-I"]).mode_after(Mode::Insert);
|
let mut cx = cx.binding(["shift-i"]).mode_after(Mode::Insert);
|
||||||
cx.assert("The q|uick", "|The quick");
|
cx.assert("The q|uick", "|The quick");
|
||||||
cx.assert(" The q|uick", " |The quick");
|
cx.assert(" The q|uick", " |The quick");
|
||||||
cx.assert("|", "|");
|
cx.assert("|", "|");
|
||||||
|
@ -817,7 +817,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_delete_to_end_of_line(cx: &mut gpui::TestAppContext) {
|
async fn test_delete_to_end_of_line(cx: &mut gpui::TestAppContext) {
|
||||||
let cx = VimTestContext::new(cx, true).await;
|
let cx = VimTestContext::new(cx, true).await;
|
||||||
let mut cx = cx.binding(["shift-D"]);
|
let mut cx = cx.binding(["shift-d"]);
|
||||||
cx.assert(
|
cx.assert(
|
||||||
indoc! {"
|
indoc! {"
|
||||||
The q|uick
|
The q|uick
|
||||||
|
@ -858,7 +858,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_delete_left(cx: &mut gpui::TestAppContext) {
|
async fn test_delete_left(cx: &mut gpui::TestAppContext) {
|
||||||
let cx = VimTestContext::new(cx, true).await;
|
let cx = VimTestContext::new(cx, true).await;
|
||||||
let mut cx = cx.binding(["shift-X"]);
|
let mut cx = cx.binding(["shift-x"]);
|
||||||
cx.assert("Te|st", "T|st");
|
cx.assert("Te|st", "T|st");
|
||||||
cx.assert("T|est", "|est");
|
cx.assert("T|est", "|est");
|
||||||
cx.assert("|Test", "|Test");
|
cx.assert("|Test", "|Test");
|
||||||
|
@ -956,7 +956,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_insert_line_above(cx: &mut gpui::TestAppContext) {
|
async fn test_insert_line_above(cx: &mut gpui::TestAppContext) {
|
||||||
let cx = VimTestContext::new(cx, true).await;
|
let cx = VimTestContext::new(cx, true).await;
|
||||||
let mut cx = cx.binding(["shift-O"]).mode_after(Mode::Insert);
|
let mut cx = cx.binding(["shift-o"]).mode_after(Mode::Insert);
|
||||||
|
|
||||||
cx.assert(
|
cx.assert(
|
||||||
"|",
|
"|",
|
||||||
|
|
|
@ -139,7 +139,7 @@ mod test {
|
||||||
test"},
|
test"},
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut cx = cx.binding(["c", "shift-W"]);
|
let mut cx = cx.binding(["c", "shift-w"]);
|
||||||
cx.assert("Test te|st-test test", "Test te| test");
|
cx.assert("Test te|st-test test", "Test te| test");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ mod test {
|
||||||
test"},
|
test"},
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut cx = cx.binding(["c", "shift-E"]);
|
let mut cx = cx.binding(["c", "shift-e"]);
|
||||||
cx.assert("Test te|st-test test", "Test te| test");
|
cx.assert("Test te|st-test test", "Test te| test");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,14 +204,14 @@ mod test {
|
||||||
test"},
|
test"},
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut cx = cx.binding(["c", "shift-B"]);
|
let mut cx = cx.binding(["c", "shift-b"]);
|
||||||
cx.assert("Test test-test |test", "Test |test");
|
cx.assert("Test test-test |test", "Test |test");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_change_end_of_line(cx: &mut gpui::TestAppContext) {
|
async fn test_change_end_of_line(cx: &mut gpui::TestAppContext) {
|
||||||
let cx = VimTestContext::new(cx, true).await;
|
let cx = VimTestContext::new(cx, true).await;
|
||||||
let mut cx = cx.binding(["c", "shift-$"]).mode_after(Mode::Insert);
|
let mut cx = cx.binding(["c", "$"]).mode_after(Mode::Insert);
|
||||||
cx.assert(
|
cx.assert(
|
||||||
indoc! {"
|
indoc! {"
|
||||||
The q|uick
|
The q|uick
|
||||||
|
@ -347,7 +347,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_change_end_of_document(cx: &mut gpui::TestAppContext) {
|
async fn test_change_end_of_document(cx: &mut gpui::TestAppContext) {
|
||||||
let cx = VimTestContext::new(cx, true).await;
|
let cx = VimTestContext::new(cx, true).await;
|
||||||
let mut cx = cx.binding(["c", "shift-G"]).mode_after(Mode::Insert);
|
let mut cx = cx.binding(["c", "shift-g"]).mode_after(Mode::Insert);
|
||||||
cx.assert(
|
cx.assert(
|
||||||
indoc! {"
|
indoc! {"
|
||||||
The quick
|
The quick
|
||||||
|
|
|
@ -109,7 +109,7 @@ mod test {
|
||||||
test"},
|
test"},
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut cx = cx.binding(["d", "shift-W"]);
|
let mut cx = cx.binding(["d", "shift-w"]);
|
||||||
cx.assert("Test te|st-test test", "Test te|test");
|
cx.assert("Test te|st-test test", "Test te|test");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ mod test {
|
||||||
test"},
|
test"},
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut cx = cx.binding(["d", "shift-E"]);
|
let mut cx = cx.binding(["d", "shift-e"]);
|
||||||
cx.assert("Test te|st-test test", "Test te| test");
|
cx.assert("Test te|st-test test", "Test te| test");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,14 +176,14 @@ mod test {
|
||||||
test"},
|
test"},
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut cx = cx.binding(["d", "shift-B"]);
|
let mut cx = cx.binding(["d", "shift-b"]);
|
||||||
cx.assert("Test test-test |test", "Test |test");
|
cx.assert("Test test-test |test", "Test |test");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_delete_end_of_line(cx: &mut gpui::TestAppContext) {
|
async fn test_delete_end_of_line(cx: &mut gpui::TestAppContext) {
|
||||||
let cx = VimTestContext::new(cx, true).await;
|
let cx = VimTestContext::new(cx, true).await;
|
||||||
let mut cx = cx.binding(["d", "shift-$"]);
|
let mut cx = cx.binding(["d", "$"]);
|
||||||
cx.assert(
|
cx.assert(
|
||||||
indoc! {"
|
indoc! {"
|
||||||
The q|uick
|
The q|uick
|
||||||
|
@ -304,7 +304,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_delete_end_of_document(cx: &mut gpui::TestAppContext) {
|
async fn test_delete_end_of_document(cx: &mut gpui::TestAppContext) {
|
||||||
let cx = VimTestContext::new(cx, true).await;
|
let cx = VimTestContext::new(cx, true).await;
|
||||||
let mut cx = cx.binding(["d", "shift-G"]);
|
let mut cx = cx.binding(["d", "shift-g"]);
|
||||||
cx.assert(
|
cx.assert(
|
||||||
indoc! {"
|
indoc! {"
|
||||||
The quick
|
The quick
|
||||||
|
|
|
@ -422,7 +422,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_visual_line_delete(cx: &mut gpui::TestAppContext) {
|
async fn test_visual_line_delete(cx: &mut gpui::TestAppContext) {
|
||||||
let cx = VimTestContext::new(cx, true).await;
|
let cx = VimTestContext::new(cx, true).await;
|
||||||
let mut cx = cx.binding(["shift-V", "x"]);
|
let mut cx = cx.binding(["shift-v", "x"]);
|
||||||
cx.assert(
|
cx.assert(
|
||||||
indoc! {"
|
indoc! {"
|
||||||
The qu|ick brown
|
The qu|ick brown
|
||||||
|
@ -457,7 +457,7 @@ mod test {
|
||||||
The quick brown
|
The quick brown
|
||||||
fox ju|mps over"},
|
fox ju|mps over"},
|
||||||
);
|
);
|
||||||
let mut cx = cx.binding(["shift-V", "j", "x"]);
|
let mut cx = cx.binding(["shift-v", "j", "x"]);
|
||||||
cx.assert(
|
cx.assert(
|
||||||
indoc! {"
|
indoc! {"
|
||||||
The qu|ick brown
|
The qu|ick brown
|
||||||
|
@ -558,7 +558,7 @@ mod test {
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_visual_line_change(cx: &mut gpui::TestAppContext) {
|
async fn test_visual_line_change(cx: &mut gpui::TestAppContext) {
|
||||||
let cx = VimTestContext::new(cx, true).await;
|
let cx = VimTestContext::new(cx, true).await;
|
||||||
let mut cx = cx.binding(["shift-V", "c"]).mode_after(Mode::Insert);
|
let mut cx = cx.binding(["shift-v", "c"]).mode_after(Mode::Insert);
|
||||||
cx.assert(
|
cx.assert(
|
||||||
indoc! {"
|
indoc! {"
|
||||||
The qu|ick brown
|
The qu|ick brown
|
||||||
|
@ -597,7 +597,7 @@ mod test {
|
||||||
fox jumps over
|
fox jumps over
|
||||||
|"},
|
|"},
|
||||||
);
|
);
|
||||||
let mut cx = cx.binding(["shift-V", "j", "c"]).mode_after(Mode::Insert);
|
let mut cx = cx.binding(["shift-v", "j", "c"]).mode_after(Mode::Insert);
|
||||||
cx.assert(
|
cx.assert(
|
||||||
indoc! {"
|
indoc! {"
|
||||||
The qu|ick brown
|
The qu|ick brown
|
||||||
|
|
|
@ -949,11 +949,11 @@ impl Workspace {
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
app_state: Arc<AppState>,
|
app_state: Arc<AppState>,
|
||||||
mut callback: F,
|
callback: F,
|
||||||
) -> T
|
) -> T
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
F: FnMut(&mut Workspace, &mut ViewContext<Workspace>) -> T,
|
F: FnOnce(&mut Workspace, &mut ViewContext<Workspace>) -> T,
|
||||||
{
|
{
|
||||||
if self.project.read(cx).is_local() {
|
if self.project.read(cx).is_local() {
|
||||||
callback(self, cx)
|
callback(self, cx)
|
||||||
|
|
|
@ -3,7 +3,7 @@ authors = ["Nathan Sobo <nathansobo@gmail.com>"]
|
||||||
description = "The fast, collaborative code editor."
|
description = "The fast, collaborative code editor."
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
name = "zed"
|
name = "zed"
|
||||||
version = "0.49.0"
|
version = "0.49.1"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "zed"
|
name = "zed"
|
||||||
|
|
|
@ -57,6 +57,7 @@ fn main() {
|
||||||
fs::create_dir_all(&logs_dir_path).expect("could not create logs path");
|
fs::create_dir_all(&logs_dir_path).expect("could not create logs path");
|
||||||
init_logger(&logs_dir_path);
|
init_logger(&logs_dir_path);
|
||||||
|
|
||||||
|
log::info!("========== starting zed ==========");
|
||||||
let mut app = gpui::App::new(Assets).unwrap();
|
let mut app = gpui::App::new(Assets).unwrap();
|
||||||
let app_version = ZED_APP_VERSION
|
let app_version = ZED_APP_VERSION
|
||||||
.or_else(|| app.platform().app_version().ok())
|
.or_else(|| app.platform().app_version().ok())
|
||||||
|
@ -210,6 +211,13 @@ fn init_logger(logs_dir_path: &Path) {
|
||||||
} else {
|
} else {
|
||||||
let level = LevelFilter::Info;
|
let level = LevelFilter::Info;
|
||||||
let log_file_path = logs_dir_path.join("Zed.log");
|
let log_file_path = logs_dir_path.join("Zed.log");
|
||||||
|
|
||||||
|
// Prevent log file from becoming too large.
|
||||||
|
const MAX_LOG_BYTES: u64 = 1 * 1024 * 1024;
|
||||||
|
if fs::metadata(&log_file_path).map_or(false, |metadata| metadata.len() > MAX_LOG_BYTES) {
|
||||||
|
let _ = fs::rename(&log_file_path, logs_dir_path.join("Zed.log.old"));
|
||||||
|
}
|
||||||
|
|
||||||
let log_file = OpenOptions::new()
|
let log_file = OpenOptions::new()
|
||||||
.create(true)
|
.create(true)
|
||||||
.append(true)
|
.append(true)
|
||||||
|
|
|
@ -9,6 +9,7 @@ use anyhow::{anyhow, Context, Result};
|
||||||
use assets::Assets;
|
use assets::Assets;
|
||||||
use breadcrumbs::Breadcrumbs;
|
use breadcrumbs::Breadcrumbs;
|
||||||
pub use client;
|
pub use client;
|
||||||
|
use collections::VecDeque;
|
||||||
pub use contacts_panel;
|
pub use contacts_panel;
|
||||||
use contacts_panel::ContactsPanel;
|
use contacts_panel::ContactsPanel;
|
||||||
pub use editor;
|
pub use editor;
|
||||||
|
@ -52,6 +53,7 @@ actions!(
|
||||||
Quit,
|
Quit,
|
||||||
DebugElements,
|
DebugElements,
|
||||||
OpenSettings,
|
OpenSettings,
|
||||||
|
OpenLog,
|
||||||
OpenKeymap,
|
OpenKeymap,
|
||||||
OpenDefaultSettings,
|
OpenDefaultSettings,
|
||||||
OpenDefaultKeymap,
|
OpenDefaultKeymap,
|
||||||
|
@ -65,9 +67,11 @@ actions!(
|
||||||
const MIN_FONT_SIZE: f32 = 6.0;
|
const MIN_FONT_SIZE: f32 = 6.0;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref ROOT_PATH: PathBuf = dirs::home_dir()
|
pub static ref HOME_PATH: PathBuf =
|
||||||
.expect("failed to determine home directory")
|
dirs::home_dir().expect("failed to determine home directory");
|
||||||
.join(".zed");
|
pub static ref LOG_PATH: PathBuf = HOME_PATH.join("Library/Logs/Zed/Zed.log");
|
||||||
|
pub static ref OLD_LOG_PATH: PathBuf = HOME_PATH.join("Library/Logs/Zed/Zed.log.old");
|
||||||
|
pub static ref ROOT_PATH: PathBuf = HOME_PATH.join(".zed");
|
||||||
pub static ref SETTINGS_PATH: PathBuf = ROOT_PATH.join("settings.json");
|
pub static ref SETTINGS_PATH: PathBuf = ROOT_PATH.join("settings.json");
|
||||||
pub static ref KEYMAP_PATH: PathBuf = ROOT_PATH.join("keymap.json");
|
pub static ref KEYMAP_PATH: PathBuf = ROOT_PATH.join("keymap.json");
|
||||||
}
|
}
|
||||||
|
@ -120,6 +124,12 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
cx.add_action({
|
||||||
|
let app_state = app_state.clone();
|
||||||
|
move |workspace: &mut Workspace, _: &OpenLog, cx: &mut ViewContext<Workspace>| {
|
||||||
|
open_log_file(workspace, app_state.clone(), cx);
|
||||||
|
}
|
||||||
|
});
|
||||||
cx.add_action({
|
cx.add_action({
|
||||||
let app_state = app_state.clone();
|
let app_state = app_state.clone();
|
||||||
move |_: &mut Workspace, _: &OpenKeymap, cx: &mut ViewContext<Workspace>| {
|
move |_: &mut Workspace, _: &OpenKeymap, cx: &mut ViewContext<Workspace>| {
|
||||||
|
@ -407,6 +417,60 @@ fn open_config_file(
|
||||||
.detach_and_log_err(cx)
|
.detach_and_log_err(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn open_log_file(
|
||||||
|
workspace: &mut Workspace,
|
||||||
|
app_state: Arc<AppState>,
|
||||||
|
cx: &mut ViewContext<Workspace>,
|
||||||
|
) {
|
||||||
|
const MAX_LINES: usize = 1000;
|
||||||
|
|
||||||
|
workspace.with_local_workspace(cx, app_state.clone(), |_, cx| {
|
||||||
|
cx.spawn_weak(|workspace, mut cx| async move {
|
||||||
|
let (old_log, new_log) = futures::join!(
|
||||||
|
app_state.fs.load(&OLD_LOG_PATH),
|
||||||
|
app_state.fs.load(&LOG_PATH)
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(workspace) = workspace.upgrade(&cx) {
|
||||||
|
let mut lines = VecDeque::with_capacity(MAX_LINES);
|
||||||
|
for line in old_log
|
||||||
|
.iter()
|
||||||
|
.flat_map(|log| log.lines())
|
||||||
|
.chain(new_log.iter().flat_map(|log| log.lines()))
|
||||||
|
{
|
||||||
|
if lines.len() == MAX_LINES {
|
||||||
|
lines.pop_front();
|
||||||
|
}
|
||||||
|
lines.push_back(line);
|
||||||
|
}
|
||||||
|
let log = lines
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|line| [line, "\n"])
|
||||||
|
.collect::<String>();
|
||||||
|
|
||||||
|
workspace.update(&mut cx, |workspace, cx| {
|
||||||
|
let project = workspace.project().clone();
|
||||||
|
let buffer = project
|
||||||
|
.update(cx, |project, cx| project.create_buffer("", None, cx))
|
||||||
|
.expect("creating buffers on a local workspace always succeeds");
|
||||||
|
buffer.update(cx, |buffer, cx| buffer.edit([(0..0, log)], None, cx));
|
||||||
|
|
||||||
|
let buffer = cx.add_model(|cx| {
|
||||||
|
MultiBuffer::singleton(buffer, cx).with_title("Log".into())
|
||||||
|
});
|
||||||
|
workspace.add_item(
|
||||||
|
Box::new(
|
||||||
|
cx.add_view(|cx| Editor::for_multibuffer(buffer, Some(project), cx)),
|
||||||
|
),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn open_bundled_config_file(
|
fn open_bundled_config_file(
|
||||||
workspace: &mut Workspace,
|
workspace: &mut Workspace,
|
||||||
app_state: Arc<AppState>,
|
app_state: Arc<AppState>,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue