Skip to content

Commit 68d4099

Browse files
committed
feat(gui): add error display to GUI for out-of-sync and communication errors
1 parent 2951e8c commit 68d4099

File tree

11 files changed

+503
-292
lines changed

11 files changed

+503
-292
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ futures = "0.3"
2727
tracing = "0.1"
2828
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
2929
tracing-appender = "0.2"
30+
tower-lsp = "0.20"
3031

3132
geometry = { version = "0.7", registry = "substrate" }
3233
enumify = { version = "0.2", registry = "substrate" }

core/gui/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ edition = "2024"
77
lang-server = { path = "../lang-server" }
88
compiler = { path = "../compiler" }
99
gpui = { git = "https://github.com/ucb-substrate/zed", branch = "argon-dev" }
10+
anyhow = { workspace = true }
1011
smallvec = "1"
1112
rust-embed = "8"
1213
lazy_static = "1"
@@ -25,7 +26,7 @@ geometry = { version = "0.7.1", registry = "substrate" }
2526
indexmap = { workspace = true }
2627
rgb = { version = "0.8", features = ["serde"] }
2728
unicode-segmentation = "1"
28-
tower-lsp = "0.20"
29+
tower-lsp = { workspace = true }
2930
tracing = { workspace = true }
3031
tracing-subscriber = { workspace = true }
3132
tracing-appender = { workspace = true }

core/gui/src/editor/canvas.rs

Lines changed: 116 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,30 +1293,28 @@ impl LayoutCanvas {
12931293
.find(|name| !names.contains(name))
12941294
.unwrap();
12951295

1296-
if state
1297-
.lang_server_client
1298-
.draw_rect(
1299-
scope.span.clone(),
1300-
rect_name,
1301-
compile::BasicRect {
1302-
layer: state
1303-
.layers
1304-
.read(cx)
1305-
.selected_layer
1306-
.clone()
1307-
.map(|s| s.to_string()),
1308-
x0: p0p.x as f64,
1309-
y0: p0p.y as f64,
1310-
x1: p1p.x as f64,
1311-
y1: p1p.y as f64,
1312-
construction: false,
1313-
},
1314-
)
1315-
.is_none()
1316-
{
1317-
Some("inconsistent editor and GUI state".into())
1318-
} else {
1319-
None
1296+
match state.lang_server_client.draw_rect(
1297+
scope.span.clone(),
1298+
rect_name,
1299+
compile::BasicRect {
1300+
layer: state
1301+
.layers
1302+
.read(cx)
1303+
.selected_layer
1304+
.clone()
1305+
.map(|s| s.to_string()),
1306+
x0: p0p.x as f64,
1307+
y0: p0p.y as f64,
1308+
x1: p1p.x as f64,
1309+
y1: p1p.y as f64,
1310+
construction: false,
1311+
},
1312+
) {
1313+
Ok(None) => Some(
1314+
"inconsistent editor and GUI state".into(),
1315+
),
1316+
Ok(Some(_)) => None,
1317+
Err(e) => Some(format!("{e}").into()),
13201318
}
13211319
} else {
13221320
Some("no cell to edit".into())
@@ -1332,15 +1330,25 @@ impl LayoutCanvas {
13321330
rect_tool.p0 = Some(p0);
13331331
}
13341332
} else {
1335-
state.lang_server_client.show_message(
1333+
let res = state.lang_server_client.show_message(
13361334
MessageType::ERROR,
13371335
"Cannot draw on an invisible layer.",
13381336
);
1337+
if let Err(e) = res {
1338+
self.state.update(cx, |state, _cx| {
1339+
state.fatal_error = Some(format!("{e}").into());
1340+
});
1341+
}
13391342
}
13401343
} else {
1341-
state
1344+
let res = state
13421345
.lang_server_client
13431346
.show_message(MessageType::ERROR, "No layer has been selected.");
1347+
if let Err(e) = res {
1348+
self.state.update(cx, |state, _cx| {
1349+
state.fatal_error = Some(format!("{e}").into());
1350+
});
1351+
}
13441352
}
13451353
}
13461354
ToolState::DrawDim(dim_tool) => {
@@ -1539,38 +1547,36 @@ impl LayoutCanvas {
15391547
};
15401548

15411549
let value = format!("{:?}", edge.2.stop - edge.2.start);
1542-
state
1543-
.lang_server_client
1544-
.draw_dimension(
1545-
cell.output.cells[&selected_scope_addr.cell].scopes
1546-
[&selected_scope_addr.scope]
1547-
.span
1548-
.clone(),
1549-
DimensionParams {
1550-
p: format!("{}.{}", edge.0, right),
1551-
n: format!("{}.{}", edge.0, left),
1552-
value: value.clone(),
1553-
coord: if coord > edge.2.coord {
1554-
format!(
1555-
"{}.{} + {}",
1556-
edge.0,
1557-
edge.1,
1558-
coord - edge.2.coord
1559-
)
1560-
} else {
1561-
format!(
1562-
"{}.{} - {}",
1563-
edge.0,
1564-
edge.1,
1565-
edge.2.coord - coord
1566-
)
1567-
},
1568-
pstop: format!("{}.{}", edge.0, edge.1),
1569-
nstop: format!("{}.{}", edge.0, edge.1),
1570-
horiz: horiz.to_string(),
1550+
let res = state.lang_server_client.draw_dimension(
1551+
cell.output.cells[&selected_scope_addr.cell].scopes
1552+
[&selected_scope_addr.scope]
1553+
.span
1554+
.clone(),
1555+
DimensionParams {
1556+
p: format!("{}.{}", edge.0, right),
1557+
n: format!("{}.{}", edge.0, left),
1558+
value: value.clone(),
1559+
coord: if coord > edge.2.coord {
1560+
format!("{}.{} + {}", edge.0, edge.1, coord - edge.2.coord)
1561+
} else {
1562+
format!("{}.{} - {}", edge.0, edge.1, edge.2.coord - coord)
15711563
},
1572-
)
1573-
.map(|span| (span, value))
1564+
pstop: format!("{}.{}", edge.0, edge.1),
1565+
nstop: format!("{}.{}", edge.0, edge.1),
1566+
horiz: horiz.to_string(),
1567+
},
1568+
);
1569+
if let Some(error) = match &res {
1570+
Ok(None) => Some("inconsistent editor and GUI state".into()),
1571+
Ok(Some(_)) => None,
1572+
Err(e) => Some(format!("{e}").into()),
1573+
} {
1574+
self.state.update(cx, |state, _cx| {
1575+
state.fatal_error = Some(error);
1576+
});
1577+
}
1578+
1579+
res.unwrap_or_default().map(|span| (span, value))
15741580
} else if dim_tool.edges.len() == 2 {
15751581
match (&dim_tool.edges[0], &dim_tool.edges[1]) {
15761582
(DimEdge::Edge(edge0), DimEdge::Edge(edge1)) => {
@@ -1595,7 +1601,7 @@ impl LayoutCanvas {
15951601
format!("- {}", intended_coord - coord)
15961602
};
15971603
let value = format!("{:?}", right.2.coord - left.2.coord);
1598-
state.lang_server_client.draw_dimension(
1604+
let res = state.lang_server_client.draw_dimension(
15991605
cell.output.cells[&selected_scope_addr.cell].scopes
16001606
[&selected_scope_addr.scope]
16011607
.span
@@ -1625,7 +1631,20 @@ impl LayoutCanvas {
16251631
),
16261632
horiz: horiz.to_string(),
16271633
},
1628-
).map(|span| (span, value))
1634+
);
1635+
if let Some(error) = match &res {
1636+
Ok(None) => {
1637+
Some("inconsistent editor and GUI state".into())
1638+
}
1639+
Ok(Some(_)) => None,
1640+
Err(e) => Some(format!("{e}").into()),
1641+
} {
1642+
self.state.update(cx, |state, _cx| {
1643+
state.fatal_error = Some(error);
1644+
});
1645+
}
1646+
1647+
res.unwrap_or_default().map(|span| (span, value))
16291648
}
16301649
(DimEdge::X0 | DimEdge::Y0, DimEdge::Edge(edge))
16311650
| (DimEdge::Edge(edge), DimEdge::X0 | DimEdge::Y0) => {
@@ -1665,24 +1684,34 @@ impl LayoutCanvas {
16651684
coord.clone(),
16661685
)
16671686
};
1668-
state
1669-
.lang_server_client
1670-
.draw_dimension(
1671-
cell.output.cells[&selected_scope_addr.cell].scopes
1672-
[&selected_scope_addr.scope]
1673-
.span
1674-
.clone(),
1675-
DimensionParams {
1676-
p,
1677-
n,
1678-
value: value.clone(),
1679-
coord,
1680-
pstop,
1681-
nstop,
1682-
horiz: horiz.to_string(),
1683-
},
1684-
)
1685-
.map(|span| (span, value))
1687+
let res = state.lang_server_client.draw_dimension(
1688+
cell.output.cells[&selected_scope_addr.cell].scopes
1689+
[&selected_scope_addr.scope]
1690+
.span
1691+
.clone(),
1692+
DimensionParams {
1693+
p,
1694+
n,
1695+
value: value.clone(),
1696+
coord,
1697+
pstop,
1698+
nstop,
1699+
horiz: horiz.to_string(),
1700+
},
1701+
);
1702+
if let Some(error) = match &res {
1703+
Ok(None) => {
1704+
Some("inconsistent editor and GUI state".into())
1705+
}
1706+
Ok(Some(_)) => None,
1707+
Err(e) => Some(format!("{e}").into()),
1708+
} {
1709+
self.state.update(cx, |state, _cx| {
1710+
state.fatal_error = Some(error);
1711+
});
1712+
}
1713+
1714+
res.unwrap_or_default().map(|span| (span, value))
16861715
}
16871716
_ => unreachable!(),
16881717
}
@@ -1732,10 +1761,18 @@ impl LayoutCanvas {
17321761
}
17331762
if let Some(span) = selected_obj {
17341763
select_tool.selected_obj = Some(span.clone());
1735-
self.state
1764+
if let Err(e) = self
1765+
.state
17361766
.read(cx)
17371767
.lang_server_client
1738-
.select_rect(span.clone());
1768+
.select_rect(span.clone())
1769+
{
1770+
self.state.update(cx, |state, cx| {
1771+
state.fatal_error =
1772+
Some(format!("Editing disabled due to error {e}").into());
1773+
cx.notify();
1774+
});
1775+
}
17391776
} else {
17401777
select_tool.selected_obj = None;
17411778
}

core/gui/src/editor/input.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -252,30 +252,46 @@ impl TextInput {
252252

253253
fn command_prompt_enter(&mut self, _: &Enter, window: &mut Window, cx: &mut Context<Self>) {
254254
let reset = self.state.read(cx).tool.clone().update(cx, |tool, cx| {
255-
if let ToolState::EditDim(EditDimToolState { dim, dim_mode, .. }) = tool
256-
&& self
255+
if let ToolState::EditDim(EditDimToolState { dim, dim_mode, .. }) = tool {
256+
let error = match self
257257
.state
258258
.read(cx)
259259
.lang_server_client
260260
.edit_dimension(dim.clone(), self.content.to_string())
261-
.is_some()
262-
{
263-
*tool = if *dim_mode {
264-
ToolState::DrawDim(DrawDimToolState::default())
265-
} else {
266-
ToolState::default()
261+
{
262+
Ok(None) => Some("inconsistent editor and GUI state".into()),
263+
Ok(Some(_)) => None,
264+
Err(e) => Some(format!("{e}").into()),
267265
};
268-
true
266+
if let Some(error) = error {
267+
self.state.update(cx, |state, _cx| {
268+
state.fatal_error = Some(error);
269+
});
270+
false
271+
} else {
272+
*tool = if *dim_mode {
273+
ToolState::DrawDim(DrawDimToolState::default())
274+
} else {
275+
ToolState::default()
276+
};
277+
true
278+
}
269279
} else {
270280
if let Some((command, rest)) = self.content.split_once(" ") {
271281
#[allow(clippy::single_match)]
272282
match command.trim_start_matches(":") {
273283
"openCell" => {
274-
self.state
284+
let res = self
285+
.state
275286
.read(cx)
276287
.lang_server_client
277288
.open_cell(rest.to_string());
278-
return true;
289+
if let Err(e) = &res {
290+
self.state.update(cx, |state, _cx| {
291+
state.fatal_error = Some(format!("{e}").into());
292+
});
293+
}
294+
return res.is_ok();
279295
}
280296
_ => {} // TODO: support other commands, reduce redundancy with rpc.rs
281297
}

0 commit comments

Comments
 (0)