Rearrange the terminal code to not have a cyclic dependency with the project

This commit is contained in:
Mikayla Maki 2022-12-08 10:48:28 -08:00
parent 1b8763d0cf
commit 83aefffa38
12 changed files with 270 additions and 300 deletions

4
Cargo.lock generated
View File

@ -6271,6 +6271,7 @@ dependencies = [
"mio-extras",
"ordered-float",
"procinfo",
"rand 0.8.5",
"serde",
"settings",
"shellexpand",
@ -6278,13 +6279,13 @@ dependencies = [
"smol",
"theme",
"thiserror",
"util",
]
[[package]]
name = "terminal_view"
version = "0.1.0"
dependencies = [
"alacritty_terminal",
"anyhow",
"client",
"context_menu",
@ -6307,6 +6308,7 @@ dependencies = [
"shellexpand",
"smallvec",
"smol",
"terminal",
"theme",
"thiserror",
"util",

View File

@ -2422,7 +2422,7 @@ impl Editor {
let all_edits_within_excerpt = buffer.read_with(&cx, |buffer, _| {
let excerpt_range = excerpt_range.to_offset(buffer);
buffer
.edited_ranges_for_transaction(transaction)
.edited_ranges_for_transaction::<usize>(transaction)
.all(|range| {
excerpt_range.start <= range.start
&& excerpt_range.end >= range.end

View File

@ -60,9 +60,9 @@ use std::{
atomic::{AtomicUsize, Ordering::SeqCst},
Arc,
},
thread::panicking,
time::Instant,
};
use terminal::Terminal;
use thiserror::Error;
use util::{defer, post_inc, ResultExt, TryFutureExt as _};
@ -1196,12 +1196,14 @@ impl Project {
pub fn create_terminal_connection(
&mut self,
cx: &mut ModelContext<Self>,
) -> Result<ModelHandle<TerminalConnection>> {
_cx: &mut ModelContext<Self>,
) -> Result<ModelHandle<Terminal>> {
if self.is_remote() {
return Err(anyhow!(
"creating terminals as a guest is not supported yet"
));
} else {
unimplemented!()
}
}

View File

@ -13,6 +13,7 @@ gpui = { path = "../gpui" }
settings = { path = "../settings" }
db = { path = "../db" }
theme = { path = "../theme" }
util = { path = "../util" }
alacritty_terminal = { git = "https://github.com/zed-industries/alacritty", rev = "a51dbe25d67e84d6ed4261e640d3954fbdd9be45" }
procinfo = { git = "https://github.com/zed-industries/wezterm", rev = "5cd757e5f2eb039ed0c6bb6512223e69d5efc64d", default-features = false }
smallvec = { version = "1.6", features = ["union"] }
@ -28,3 +29,6 @@ anyhow = "1"
thiserror = "1.0"
lazy_static = "1.4.0"
serde = { version = "1.0", features = ["derive"] }
[dev-dependencies]
rand = "0.8.5"

View File

@ -1,5 +1,5 @@
pub mod mappings;
mod persistence;
pub use alacritty_terminal;
use alacritty_terminal::{
ansi::{ClearMode, Handler},
@ -30,7 +30,6 @@ use mappings::mouse::{
alt_scroll, grid_point, mouse_button_report, mouse_moved_report, mouse_side, scroll_report,
};
use persistence::TERMINAL_CONNECTION;
use procinfo::LocalProcessInfo;
use settings::{AlternateScroll, Settings, Shell, TerminalBlink};
use util::ResultExt;
@ -53,8 +52,7 @@ use gpui::{
geometry::vector::{vec2f, Vector2F},
keymap::Keystroke,
scene::{MouseDown, MouseDrag, MouseScrollWheel, MouseUp},
AppContext, ClipboardItem, Entity, ModelContext, MouseButton, MouseMovedEvent,
MutableAppContext, Task,
ClipboardItem, Entity, ModelContext, MouseButton, MouseMovedEvent, Task,
};
use crate::mappings::{
@ -63,12 +61,6 @@ use crate::mappings::{
};
use lazy_static::lazy_static;
///Initialize and register all of our action handlers
pub fn init(cx: &mut MutableAppContext) {
terminal_view::init(cx);
terminal_container_view::init(cx);
}
///Scrolling is unbearably sluggish by default. Alacritty supports a configurable
///Scroll multiplier that is set to 3 by default. This will be removed when I
///Implement scroll bars.
@ -124,10 +116,10 @@ impl EventListener for ZedListener {
#[derive(Clone, Copy, Debug)]
pub struct TerminalSize {
cell_width: f32,
line_height: f32,
height: f32,
width: f32,
pub cell_width: f32,
pub line_height: f32,
pub height: f32,
pub width: f32,
}
impl TerminalSize {
@ -281,8 +273,6 @@ impl TerminalBuilder {
blink_settings: Option<TerminalBlink>,
alternate_scroll: &AlternateScroll,
window_id: usize,
item_id: ItemId,
workspace_id: WorkspaceId,
) -> Result<TerminalBuilder> {
let pty_config = {
let alac_shell = shell.clone().and_then(|shell| match shell {
@ -387,8 +377,6 @@ impl TerminalBuilder {
last_mouse_position: None,
next_link_id: 0,
selection_phase: SelectionPhase::Ended,
workspace_id,
item_id,
};
Ok(TerminalBuilder {
@ -460,9 +448,9 @@ impl TerminalBuilder {
}
#[derive(Debug, Clone)]
struct IndexedCell {
point: Point,
cell: Cell,
pub struct IndexedCell {
pub point: Point,
pub cell: Cell,
}
impl Deref for IndexedCell {
@ -474,17 +462,18 @@ impl Deref for IndexedCell {
}
}
// TODO: Un-pub
#[derive(Clone)]
pub struct TerminalContent {
cells: Vec<IndexedCell>,
mode: TermMode,
display_offset: usize,
selection_text: Option<String>,
selection: Option<SelectionRange>,
cursor: RenderableCursor,
cursor_char: char,
size: TerminalSize,
last_hovered_hyperlink: Option<(String, RangeInclusive<Point>, usize)>,
pub cells: Vec<IndexedCell>,
pub mode: TermMode,
pub display_offset: usize,
pub selection_text: Option<String>,
pub selection: Option<SelectionRange>,
pub cursor: RenderableCursor,
pub cursor_char: char,
pub size: TerminalSize,
pub last_hovered_hyperlink: Option<(String, RangeInclusive<Point>, usize)>,
}
impl Default for TerminalContent {
@ -521,19 +510,17 @@ pub struct Terminal {
/// This is only used for terminal hyperlink checking
last_mouse_position: Option<Vector2F>,
pub matches: Vec<RangeInclusive<Point>>,
last_content: TerminalContent,
pub last_content: TerminalContent,
last_synced: Instant,
sync_task: Option<Task<()>>,
selection_head: Option<Point>,
breadcrumb_text: String,
pub selection_head: Option<Point>,
pub breadcrumb_text: String,
shell_pid: u32,
shell_fd: u32,
foreground_process_info: Option<LocalProcessInfo>,
pub foreground_process_info: Option<LocalProcessInfo>,
scroll_px: f32,
next_link_id: usize,
selection_phase: SelectionPhase,
workspace_id: WorkspaceId,
item_id: ItemId,
}
impl Terminal {
@ -574,20 +561,6 @@ impl Terminal {
if self.update_process_info() {
cx.emit(Event::TitleChanged);
if let Some(foreground_info) = &self.foreground_process_info {
let cwd = foreground_info.cwd.clone();
let item_id = self.item_id;
let workspace_id = self.workspace_id;
cx.background()
.spawn(async move {
TERMINAL_CONNECTION
.save_working_directory(item_id, workspace_id, cwd)
.await
.log_err();
})
.detach();
}
}
}
AlacTermEvent::ColorRequest(idx, fun_ptr) => {
@ -1190,42 +1163,13 @@ impl Terminal {
}
}
pub fn set_workspace_id(&mut self, id: WorkspaceId, cx: &AppContext) {
let old_workspace_id = self.workspace_id;
let item_id = self.item_id;
cx.background()
.spawn(async move {
TERMINAL_CONNECTION
.update_workspace_id(id, old_workspace_id, item_id)
.await
.log_err()
})
.detach();
self.workspace_id = id;
}
pub fn find_matches(
&mut self,
query: project::search::SearchQuery,
searcher: RegexSearch,
cx: &mut ModelContext<Self>,
) -> Task<Vec<RangeInclusive<Point>>> {
let term = self.term.clone();
cx.background().spawn(async move {
let searcher = match query {
project::search::SearchQuery::Text { query, .. } => {
RegexSearch::new(query.as_ref())
}
project::search::SearchQuery::Regex { query, .. } => {
RegexSearch::new(query.as_ref())
}
};
if searcher.is_err() {
return Vec::new();
}
let searcher = searcher.unwrap();
let term = term.lock();
all_search_matches(&term, &searcher).collect()
@ -1322,14 +1266,14 @@ fn open_uri(uri: &str) -> Result<(), std::io::Error> {
#[cfg(test)]
mod tests {
use alacritty_terminal::{
index::{Column, Line, Point},
term::cell::Cell,
};
use gpui::geometry::vector::vec2f;
use rand::{thread_rng, Rng};
use rand::{rngs::ThreadRng, thread_rng, Rng};
use crate::content_index_for_mouse;
use self::terminal_test_context::TerminalTestContext;
pub mod terminal_test_context;
use crate::{content_index_for_mouse, IndexedCell, TerminalContent, TerminalSize};
#[test]
fn test_mouse_to_cell() {
@ -1346,7 +1290,7 @@ mod tests {
width: cell_size * (viewport_cells as f32),
};
let (content, cells) = TerminalTestContext::create_terminal_content(size, &mut rng);
let (content, cells) = create_terminal_content(size, &mut rng);
for i in 0..(viewport_cells - 1) {
let i = i as usize;
@ -1382,7 +1326,7 @@ mod tests {
width: 100.,
};
let (content, cells) = TerminalTestContext::create_terminal_content(size, &mut rng);
let (content, cells) = create_terminal_content(size, &mut rng);
assert_eq!(
content.cells[content_index_for_mouse(vec2f(-10., -10.), &content)].c,
@ -1393,4 +1337,37 @@ mod tests {
cells[9][9]
);
}
fn create_terminal_content(
size: TerminalSize,
rng: &mut ThreadRng,
) -> (TerminalContent, Vec<Vec<char>>) {
let mut ic = Vec::new();
let mut cells = Vec::new();
for row in 0..((size.height() / size.line_height()) as usize) {
let mut row_vec = Vec::new();
for col in 0..((size.width() / size.cell_width()) as usize) {
let cell_char = rng.gen();
ic.push(IndexedCell {
point: Point::new(Line(row as i32), Column(col)),
cell: Cell {
c: cell_char,
..Default::default()
},
});
row_vec.push(cell_char)
}
cells.push(row_vec)
}
(
TerminalContent {
cells: ic,
size,
..Default::default()
},
cells,
)
}
}

View File

@ -1,143 +0,0 @@
use std::{path::Path, time::Duration};
use alacritty_terminal::{
index::{Column, Line, Point},
term::cell::Cell,
};
use gpui::{ModelHandle, TestAppContext, ViewHandle};
use project::{Entry, Project, ProjectPath, Worktree};
use rand::{rngs::ThreadRng, Rng};
use workspace::{AppState, Workspace};
use crate::{IndexedCell, TerminalContent, TerminalSize};
pub struct TerminalTestContext<'a> {
pub cx: &'a mut TestAppContext,
}
impl<'a> TerminalTestContext<'a> {
pub fn new(cx: &'a mut TestAppContext) -> Self {
cx.set_condition_duration(Some(Duration::from_secs(5)));
TerminalTestContext { cx }
}
///Creates a worktree with 1 file: /root.txt
pub async fn blank_workspace(&mut self) -> (ModelHandle<Project>, ViewHandle<Workspace>) {
let params = self.cx.update(AppState::test);
let project = Project::test(params.fs.clone(), [], self.cx).await;
let (_, workspace) = self.cx.add_window(|cx| {
Workspace::new(
Default::default(),
0,
project.clone(),
|_, _| unimplemented!(),
cx,
)
});
(project, workspace)
}
///Creates a worktree with 1 folder: /root{suffix}/
pub async fn create_folder_wt(
&mut self,
project: ModelHandle<Project>,
path: impl AsRef<Path>,
) -> (ModelHandle<Worktree>, Entry) {
self.create_wt(project, true, path).await
}
///Creates a worktree with 1 file: /root{suffix}.txt
pub async fn create_file_wt(
&mut self,
project: ModelHandle<Project>,
path: impl AsRef<Path>,
) -> (ModelHandle<Worktree>, Entry) {
self.create_wt(project, false, path).await
}
async fn create_wt(
&mut self,
project: ModelHandle<Project>,
is_dir: bool,
path: impl AsRef<Path>,
) -> (ModelHandle<Worktree>, Entry) {
let (wt, _) = project
.update(self.cx, |project, cx| {
project.find_or_create_local_worktree(path, true, cx)
})
.await
.unwrap();
let entry = self
.cx
.update(|cx| {
wt.update(cx, |wt, cx| {
wt.as_local()
.unwrap()
.create_entry(Path::new(""), is_dir, cx)
})
})
.await
.unwrap();
(wt, entry)
}
pub fn insert_active_entry_for(
&mut self,
wt: ModelHandle<Worktree>,
entry: Entry,
project: ModelHandle<Project>,
) {
self.cx.update(|cx| {
let p = ProjectPath {
worktree_id: wt.read(cx).id(),
path: entry.path,
};
project.update(cx, |project, cx| project.set_active_path(Some(p), cx));
});
}
pub fn create_terminal_content(
size: TerminalSize,
rng: &mut ThreadRng,
) -> (TerminalContent, Vec<Vec<char>>) {
let mut ic = Vec::new();
let mut cells = Vec::new();
for row in 0..((size.height() / size.line_height()) as usize) {
let mut row_vec = Vec::new();
for col in 0..((size.width() / size.cell_width()) as usize) {
let cell_char = rng.gen();
ic.push(IndexedCell {
point: Point::new(Line(row as i32), Column(col)),
cell: Cell {
c: cell_char,
..Default::default()
},
});
row_vec.push(cell_char)
}
cells.push(row_vec)
}
(
TerminalContent {
cells: ic,
size,
..Default::default()
},
cells,
)
}
}
impl<'a> Drop for TerminalTestContext<'a> {
fn drop(&mut self) {
self.cx.set_condition_duration(None);
}
}

View File

@ -18,8 +18,8 @@ theme = { path = "../theme" }
util = { path = "../util" }
workspace = { path = "../workspace" }
db = { path = "../db" }
alacritty_terminal = { git = "https://github.com/zed-industries/alacritty", rev = "a51dbe25d67e84d6ed4261e640d3954fbdd9be45" }
procinfo = { git = "https://github.com/zed-industries/wezterm", rev = "5cd757e5f2eb039ed0c6bb6512223e69d5efc64d", default-features = false }
terminal = { path = "../terminal" }
smallvec = { version = "1.6", features = ["union"] }
smol = "1.2.5"
mio-extras = "2.0.6"

View File

@ -1,11 +1,12 @@
use std::path::PathBuf;
use db::{define_connection, query, sqlez_macros::sql};
use workspace::{WorkspaceDb, WorkspaceId};
type ModelId = usize;
define_connection! {
pub static ref TERMINAL_CONNECTION: TerminalDb<()> =
pub static ref TERMINAL_DB: TerminalDb<WorkspaceDb> =
&[sql!(
CREATE TABLE terminals (
workspace_id INTEGER,
@ -34,7 +35,7 @@ impl TerminalDb {
query! {
pub async fn save_working_directory(
item_id: ModelId,
workspace_id: WorkspaceId,
workspace_id: i64,
working_directory: PathBuf
) -> Result<()> {
INSERT OR REPLACE INTO terminals(item_id, workspace_id, working_directory)

View File

@ -1,13 +1,18 @@
use crate::persistence::TERMINAL_CONNECTION;
use crate::terminal_view::TerminalView;
use crate::{Event, TerminalBuilder, TerminalError};
mod persistence;
pub mod terminal_element;
pub mod terminal_view;
use crate::persistence::TERMINAL_DB;
use crate::terminal_view::TerminalView;
use terminal::alacritty_terminal::index::Point;
use terminal::{Event, TerminalBuilder, TerminalError};
use alacritty_terminal::index::Point;
use dirs::home_dir;
use gpui::{
actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MutableAppContext, Task,
View, ViewContext, ViewHandle, WeakViewHandle,
};
use terminal_view::regex_search_for_query;
use util::{truncate_and_trailoff, ResultExt};
use workspace::searchable::{SearchEvent, SearchOptions, SearchableItem, SearchableItemHandle};
use workspace::{
@ -30,6 +35,8 @@ pub fn init(cx: &mut MutableAppContext) {
cx.add_action(TerminalContainer::deploy);
register_deserializable_item::<TerminalContainer>(cx);
terminal_view::init(cx);
}
//Make terminal view an enum, that can give you views for the error and non-error states
@ -92,7 +99,7 @@ impl TerminalContainer {
pub fn new(
working_directory: Option<PathBuf>,
modal: bool,
workspace_id: WorkspaceId,
_workspace_id: WorkspaceId,
cx: &mut ViewContext<Self>,
) -> Self {
let settings = cx.global::<Settings>();
@ -119,8 +126,6 @@ impl TerminalContainer {
settings.terminal_overrides.blinking.clone(),
scroll,
cx.window_id(),
cx.view_id(),
workspace_id,
) {
Ok(terminal) => {
let terminal = cx.add_model(|cx| terminal.subscribe(cx));
@ -389,7 +394,7 @@ impl Item for TerminalContainer {
item_id: workspace::ItemId,
cx: &mut ViewContext<Pane>,
) -> Task<anyhow::Result<ViewHandle<Self>>> {
let working_directory = TERMINAL_CONNECTION.get_working_directory(item_id, workspace_id);
let working_directory = TERMINAL_DB.get_working_directory(item_id, workspace_id);
Task::ready(Ok(cx.add_view(|cx| {
TerminalContainer::new(
working_directory.log_err().flatten(),
@ -400,11 +405,14 @@ impl Item for TerminalContainer {
})))
}
fn added_to_workspace(&mut self, workspace: &mut Workspace, cx: &mut ViewContext<Self>) {
if let Some(connected) = self.connected() {
let id = workspace.database_id();
let terminal_handle = connected.read(cx).terminal().clone();
terminal_handle.update(cx, |terminal, cx| terminal.set_workspace_id(id, cx))
fn added_to_workspace(&mut self, _workspace: &mut Workspace, cx: &mut ViewContext<Self>) {
if let Some(_connected) = self.connected() {
// let id = workspace.database_id();
// let terminal_handle = connected.read(cx).terminal().clone();
//TODO
cx.background()
.spawn(TERMINAL_DB.update_workspace_id(0, 0, 0))
.detach();
}
}
}
@ -477,7 +485,11 @@ impl SearchableItem for TerminalContainer {
) -> Task<Vec<Self::Match>> {
if let TerminalContainerContent::Connected(connected) = &self.content {
let terminal = connected.read(cx).terminal().clone();
terminal.update(cx, |term, cx| term.find_matches(query, cx))
if let Some(searcher) = regex_search_for_query(query) {
terminal.update(cx, |term, cx| term.find_matches(searcher, cx))
} else {
cx.background().spawn(async { Vec::new() })
}
} else {
Task::ready(Vec::new())
}
@ -585,21 +597,20 @@ mod tests {
use super::*;
use gpui::TestAppContext;
use project::{Entry, Worktree};
use workspace::AppState;
use std::path::Path;
use crate::tests::terminal_test_context::TerminalTestContext;
///Working directory calculation tests
///No Worktrees in project -> home_dir()
#[gpui::test]
async fn no_worktree(cx: &mut TestAppContext) {
//Setup variables
let mut cx = TerminalTestContext::new(cx);
let (project, workspace) = cx.blank_workspace().await;
let (project, workspace) = blank_workspace(cx).await;
//Test
cx.cx.read(|cx| {
cx.read(|cx| {
let workspace = workspace.read(cx);
let active_entry = project.read(cx).active_entry();
@ -619,11 +630,10 @@ mod tests {
async fn no_active_entry_worktree_is_file(cx: &mut TestAppContext) {
//Setup variables
let mut cx = TerminalTestContext::new(cx);
let (project, workspace) = cx.blank_workspace().await;
cx.create_file_wt(project.clone(), "/root.txt").await;
let (project, workspace) = blank_workspace(cx).await;
create_file_wt(project.clone(), "/root.txt", cx).await;
cx.cx.read(|cx| {
cx.read(|cx| {
let workspace = workspace.read(cx);
let active_entry = project.read(cx).active_entry();
@ -642,12 +652,11 @@ mod tests {
#[gpui::test]
async fn no_active_entry_worktree_is_dir(cx: &mut TestAppContext) {
//Setup variables
let mut cx = TerminalTestContext::new(cx);
let (project, workspace) = cx.blank_workspace().await;
let (_wt, _entry) = cx.create_folder_wt(project.clone(), "/root/").await;
let (project, workspace) = blank_workspace(cx).await;
let (_wt, _entry) = create_folder_wt(project.clone(), "/root/", cx).await;
//Test
cx.cx.update(|cx| {
cx.update(|cx| {
let workspace = workspace.read(cx);
let active_entry = project.read(cx).active_entry();
@ -665,14 +674,14 @@ mod tests {
#[gpui::test]
async fn active_entry_worktree_is_file(cx: &mut TestAppContext) {
//Setup variables
let mut cx = TerminalTestContext::new(cx);
let (project, workspace) = cx.blank_workspace().await;
let (_wt, _entry) = cx.create_folder_wt(project.clone(), "/root1/").await;
let (wt2, entry2) = cx.create_file_wt(project.clone(), "/root2.txt").await;
cx.insert_active_entry_for(wt2, entry2, project.clone());
let (project, workspace) = blank_workspace(cx).await;
let (_wt, _entry) = create_folder_wt(project.clone(), "/root1/", cx).await;
let (wt2, entry2) = create_file_wt(project.clone(), "/root2.txt", cx).await;
insert_active_entry_for(wt2, entry2, project.clone(), cx);
//Test
cx.cx.update(|cx| {
cx.update(|cx| {
let workspace = workspace.read(cx);
let active_entry = project.read(cx).active_entry();
@ -689,14 +698,13 @@ mod tests {
#[gpui::test]
async fn active_entry_worktree_is_dir(cx: &mut TestAppContext) {
//Setup variables
let mut cx = TerminalTestContext::new(cx);
let (project, workspace) = cx.blank_workspace().await;
let (_wt, _entry) = cx.create_folder_wt(project.clone(), "/root1/").await;
let (wt2, entry2) = cx.create_folder_wt(project.clone(), "/root2/").await;
cx.insert_active_entry_for(wt2, entry2, project.clone());
let (project, workspace) = blank_workspace(cx).await;
let (_wt, _entry) = create_folder_wt(project.clone(), "/root1/", cx).await;
let (wt2, entry2) = create_folder_wt(project.clone(), "/root2/", cx).await;
insert_active_entry_for(wt2, entry2, project.clone(), cx);
//Test
cx.cx.update(|cx| {
cx.update(|cx| {
let workspace = workspace.read(cx);
let active_entry = project.read(cx).active_entry();
@ -708,4 +716,84 @@ mod tests {
assert_eq!(res, Some((Path::new("/root1/")).to_path_buf()));
});
}
///Creates a worktree with 1 file: /root.txt
pub async fn blank_workspace(
cx: &mut TestAppContext,
) -> (ModelHandle<Project>, ViewHandle<Workspace>) {
let params = cx.update(AppState::test);
let project = Project::test(params.fs.clone(), [], cx).await;
let (_, workspace) = cx.add_window(|cx| {
Workspace::new(
Default::default(),
0,
project.clone(),
|_, _| unimplemented!(),
cx,
)
});
(project, workspace)
}
///Creates a worktree with 1 folder: /root{suffix}/
async fn create_folder_wt(
project: ModelHandle<Project>,
path: impl AsRef<Path>,
cx: &mut TestAppContext,
) -> (ModelHandle<Worktree>, Entry) {
create_wt(project, true, path, cx).await
}
///Creates a worktree with 1 file: /root{suffix}.txt
async fn create_file_wt(
project: ModelHandle<Project>,
path: impl AsRef<Path>,
cx: &mut TestAppContext,
) -> (ModelHandle<Worktree>, Entry) {
create_wt(project, false, path, cx).await
}
async fn create_wt(
project: ModelHandle<Project>,
is_dir: bool,
path: impl AsRef<Path>,
cx: &mut TestAppContext,
) -> (ModelHandle<Worktree>, Entry) {
let (wt, _) = project
.update(cx, |project, cx| {
project.find_or_create_local_worktree(path, true, cx)
})
.await
.unwrap();
let entry = cx
.update(|cx| {
wt.update(cx, |wt, cx| {
wt.as_local()
.unwrap()
.create_entry(Path::new(""), is_dir, cx)
})
})
.await
.unwrap();
(wt, entry)
}
pub fn insert_active_entry_for(
wt: ModelHandle<Worktree>,
entry: Entry,
project: ModelHandle<Project>,
cx: &mut TestAppContext,
) {
cx.update(|cx| {
let p = ProjectPath {
worktree_id: wt.read(cx).id(),
path: entry.path,
};
project.update(cx, |project, cx| project.set_active_path(Some(p), cx));
});
}
}

View File

@ -1,9 +1,3 @@
use alacritty_terminal::{
ansi::{Color as AnsiColor, Color::Named, CursorShape as AlacCursorShape, NamedColor},
grid::Dimensions,
index::Point,
term::{cell::Flags, TermMode},
};
use editor::{Cursor, HighlightedRange, HighlightedRangeLine};
use gpui::{
color::Color,
@ -22,17 +16,23 @@ use itertools::Itertools;
use language::CursorShape;
use ordered_float::OrderedFloat;
use settings::Settings;
use terminal::{
alacritty_terminal::{
ansi::{Color as AnsiColor, CursorShape as AlacCursorShape, NamedColor},
grid::Dimensions,
index::Point,
term::{cell::Flags, TermMode},
},
mappings::colors::convert_color,
IndexedCell, Terminal, TerminalContent, TerminalSize,
};
use theme::TerminalStyle;
use util::ResultExt;
use std::{fmt::Debug, ops::RangeInclusive};
use std::{mem, ops::Range};
use crate::{
mappings::colors::convert_color,
terminal_view::{DeployContextMenu, TerminalView},
IndexedCell, Terminal, TerminalContent, TerminalSize,
};
use crate::terminal_view::{DeployContextMenu, TerminalView};
///The information generated during layout that is nescessary for painting
pub struct LayoutState {
@ -198,7 +198,10 @@ impl TerminalElement {
//Expand background rect range
{
if matches!(bg, Named(NamedColor::Background)) {
if matches!(
bg,
terminal::alacritty_terminal::ansi::Color::Named(NamedColor::Background)
) {
//Continue to next cell, resetting variables if nescessary
cur_alac_color = None;
if let Some(rect) = cur_rect {
@ -299,7 +302,7 @@ impl TerminalElement {
///Convert the Alacritty cell styles to GPUI text styles and background color
fn cell_style(
indexed: &IndexedCell,
fg: AnsiColor,
fg: terminal::alacritty_terminal::ansi::Color,
style: &TerminalStyle,
text_style: &TextStyle,
font_cache: &FontCache,
@ -636,7 +639,7 @@ impl Element for TerminalElement {
//Layout cursor. Rectangle is used for IME, so we should lay it out even
//if we don't end up showing it.
let cursor = if let AlacCursorShape::Hidden = cursor.shape {
let cursor = if let terminal::alacritty_terminal::ansi::CursorShape::Hidden = cursor.shape {
None
} else {
let cursor_point = DisplayCursor::from(cursor.point, *display_offset);

View File

@ -1,6 +1,5 @@
use std::{ops::RangeInclusive, time::Duration};
use std::{ops::RangeInclusive, path::PathBuf, time::Duration};
use alacritty_terminal::{index::Point, term::TermMode};
use context_menu::{ContextMenu, ContextMenuItem};
use gpui::{
actions,
@ -14,10 +13,17 @@ use gpui::{
use serde::Deserialize;
use settings::{Settings, TerminalBlink};
use smol::Timer;
use terminal::{
alacritty_terminal::{
index::Point,
term::{search::RegexSearch, TermMode},
},
Terminal,
};
use util::ResultExt;
use workspace::pane;
use crate::{terminal_element::TerminalElement, Event, Terminal};
use crate::{persistence::TERMINAL_DB, terminal_element::TerminalElement, Event};
const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
@ -95,6 +101,22 @@ impl TerminalView {
cx.emit(Event::Wakeup);
}
Event::BlinkChanged => this.blinking_on = !this.blinking_on,
Event::TitleChanged => {
// if let Some(foreground_info) = &terminal.read(cx).foreground_process_info {
// let cwd = foreground_info.cwd.clone();
//TODO
// let item_id = self.item_id;
// let workspace_id = self.workspace_id;
cx.background()
.spawn(async move {
TERMINAL_DB
.save_working_directory(0, 0, PathBuf::new())
.await
.log_err();
})
.detach();
// }
}
_ => cx.emit(*event),
})
.detach();
@ -246,8 +268,14 @@ impl TerminalView {
query: project::search::SearchQuery,
cx: &mut ViewContext<Self>,
) -> Task<Vec<RangeInclusive<Point>>> {
let searcher = regex_search_for_query(query);
if let Some(searcher) = searcher {
self.terminal
.update(cx, |term, cx| term.find_matches(query, cx))
.update(cx, |term, cx| term.find_matches(searcher, cx))
} else {
cx.background().spawn(async { Vec::new() })
}
}
pub fn terminal(&self) -> &ModelHandle<Terminal> {
@ -302,6 +330,14 @@ impl TerminalView {
}
}
pub fn regex_search_for_query(query: project::search::SearchQuery) -> Option<RegexSearch> {
let searcher = match query {
project::search::SearchQuery::Text { query, .. } => RegexSearch::new(&query),
project::search::SearchQuery::Regex { query, .. } => RegexSearch::new(&query),
};
searcher.ok()
}
impl View for TerminalView {
fn ui_name() -> &'static str {
"Terminal"

View File

@ -32,7 +32,7 @@ use settings::{
use smol::process::Command;
use std::fs::OpenOptions;
use std::{env, ffi::OsStr, panic, path::PathBuf, sync::Arc, thread, time::Duration};
use terminal::terminal_container_view::{get_working_directory, TerminalContainer};
use terminal_view::{get_working_directory, TerminalContainer};
use fs::RealFs;
use settings::watched_json::{watch_keymap_file, watch_settings_file, WatchedJsonFile};
@ -119,7 +119,7 @@ fn main() {
diagnostics::init(cx);
search::init(cx);
vim::init(cx);
terminal::init(cx);
terminal_view::init(cx);
theme_testbench::init(cx);
cx.spawn(|cx| watch_themes(fs.clone(), themes.clone(), cx))