Detailed changes
@@ -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",
@@ -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
@@ -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!()
}
}
@@ -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"] }
@@ -27,4 +28,7 @@ libc = "0.2"
anyhow = "1"
thiserror = "1.0"
lazy_static = "1.4.0"
-serde = { version = "1.0", features = ["derive"] }
+serde = { version = "1.0", features = ["derive"] }
+
+[dev-dependencies]
+rand = "0.8.5"
@@ -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 crate::content_index_for_mouse;
+ use rand::{rngs::ThreadRng, thread_rng, Rng};
- 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,
+ )
+ }
}
@@ -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);
- }
-}
@@ -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"
@@ -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)
@@ -1,13 +1,18 @@
-use crate::persistence::TERMINAL_CONNECTION;
+mod persistence;
+pub mod terminal_element;
+pub mod terminal_view;
+
+use crate::persistence::TERMINAL_DB;
use crate::terminal_view::TerminalView;
-use crate::{Event, TerminalBuilder, TerminalError};
+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));
+ });
+ }
}
@@ -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);
@@ -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>>> {
- self.terminal
- .update(cx, |term, cx| term.find_matches(query, cx))
+ let searcher = regex_search_for_query(query);
+
+ if let Some(searcher) = searcher {
+ self.terminal
+ .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"
@@ -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))