add panels

This commit is contained in:
2026-10-30 01:02:48 +03:00
parent e00f63e5da
commit 56115302df
7 changed files with 421 additions and 5 deletions
+108 -1
View File
@@ -12,8 +12,10 @@ use std::cell::{Cell, RefCell};
use std::collections::VecDeque;
use std::rc::Rc;
use crate::constants::{BOTTOM_PANEL_HEIGHT, LEFT_PANEL_WIDTH, RIGHT_PANEL_WIDTH};
use crate::editor::{Language, Workspace};
use crate::keymap::{KeyBinding, KeyMap};
use crate::panel::{PanelHandle, PanelState};
thread_local! {
/// Текущий экземпляр API. `thread_local`, потому что UI GPUI привязан к
@@ -78,6 +80,57 @@ pub struct AppApi {
workspace: Rc<RefCell<Workspace>>,
#[lua(skip)]
keymap: Rc<RefCell<KeyMap>>,
#[lua(skip)]
left_panel: PanelHandle,
#[lua(skip)]
right_panel: PanelHandle,
#[lua(skip)]
bottom_panel: PanelHandle,
}
/// API одной панели окна.
///
/// Один и тот же тип используется для `app.left_panel`, `app.right_panel` и
/// `app.bottom_panel`: отличается только состояние, на которое ссылается
/// объект. Поэтому панели управляются одинаково: `app.left_panel:open()`,
/// `app.bottom_panel:toggle()` и так далее.
#[derive(mlua::UserData)]
pub struct PanelApi {
#[lua(skip)]
state: PanelHandle,
}
impl PanelApi {
fn new(state: PanelHandle) -> Self {
Self { state }
}
}
#[mlua::userdata_impl]
impl PanelApi {
/// Открывает панель.
#[lua(infallible)]
pub fn open(&self) {
self.state.borrow_mut().open();
}
/// Закрывает панель.
#[lua(infallible)]
pub fn close(&self) {
self.state.borrow_mut().close();
}
/// Переключает панель и возвращает новое состояние.
#[lua(infallible)]
pub fn toggle(&self) -> bool {
self.state.borrow_mut().toggle()
}
/// Открыта ли панель прямо сейчас.
#[lua(infallible)]
pub fn is_open(&self) -> bool {
self.state.borrow().is_open()
}
}
#[mlua::userdata_impl]
@@ -86,7 +139,13 @@ impl AppApi {
/// [`AppApi::global`].
#[lua(skip)]
pub fn install(workspace: Rc<RefCell<Workspace>>, keymap: Rc<RefCell<KeyMap>>) -> Self {
let api = Self { workspace, keymap };
let api = Self {
workspace,
keymap,
left_panel: Rc::new(RefCell::new(PanelState::new(LEFT_PANEL_WIDTH))),
right_panel: Rc::new(RefCell::new(PanelState::new(RIGHT_PANEL_WIDTH))),
bottom_panel: Rc::new(RefCell::new(PanelState::new(BOTTOM_PANEL_HEIGHT))),
};
INSTANCE.with(|slot| *slot.borrow_mut() = Some(api.clone()));
api
}
@@ -104,6 +163,24 @@ impl AppApi {
})
}
/// Состояние левой панели (для вида).
#[lua(skip)]
pub fn left_panel_handle(&self) -> PanelHandle {
self.left_panel.clone()
}
/// Состояние правой панели (для вида).
#[lua(skip)]
pub fn right_panel_handle(&self) -> PanelHandle {
self.right_panel.clone()
}
/// Состояние нижней панели (для вида).
#[lua(skip)]
pub fn bottom_panel_handle(&self) -> PanelHandle {
self.bottom_panel.clone()
}
/// Все открытые вкладки в порядке слева направо.
#[allow(dead_code)]
// Часть публичного API приложения: вызывается внешним кодом и тестами.
@@ -287,6 +364,36 @@ impl AppApi {
self.workspace.borrow_mut().clear_language(index)
}
/// Левая панель окна.
///
/// В Lua доступна как `app.left_panel` с методами `open`, `close`,
/// `toggle` и `is_open`.
#[allow(dead_code)]
#[lua(getter, infallible)]
pub fn left_panel(&self) -> PanelApi {
PanelApi::new(self.left_panel.clone())
}
/// Правая панель окна.
///
/// В Lua доступна как `app.right_panel` с методами `open`, `close`,
/// `toggle` и `is_open`.
#[allow(dead_code)]
#[lua(getter, infallible)]
pub fn right_panel(&self) -> PanelApi {
PanelApi::new(self.right_panel.clone())
}
/// Нижняя панель окна.
///
/// В Lua доступна как `app.bottom_panel` с теми же методами, что и
/// `app.right_panel`.
#[allow(dead_code)]
#[lua(getter, infallible)]
pub fn bottom_panel(&self) -> PanelApi {
PanelApi::new(self.bottom_panel.clone())
}
/// Закрывает окно приложения.
#[lua(infallible)]
pub fn close(&self) {