M7: preserve active tab and support tab reordering

This commit is contained in:
YarilaFox
2026-10-19 14:21:52 +05:00
parent a0d1162976
commit d2dfe2ef20
15 changed files with 53 additions and 3 deletions
+39 -3
View File
@@ -92,6 +92,20 @@ pub fn specs() -> Vec<CommandSpec> {
),
spec!("file.placeImage", "Place image", "{path | data, x?, y?}", true, super::create::place_image),
spec!("file.close", "Close tab", "{index?, force? (discard unsaved changes)}", false, close),
spec!("file.moveTab", "Move tab", "{from, to} (indices among open documents)", false, |s, p| {
let from = req_index("file.moveTab", p, "from")?;
let to = req_index("file.moveTab", p, "to")?;
if from >= s.docs.len() || to >= s.docs.len() {
return Err(bad("file.moveTab", "no such document"));
}
if from != to {
let active_uid = s.docs.get(s.active).map(|d| d.uid);
let doc = s.docs.remove(from);
s.docs.insert(to, doc);
s.active = active_uid.and_then(|uid| s.docs.iter().position(|d| d.uid == uid)).unwrap_or(0);
}
Ok(json!({"index": to}))
}),
spec!(
"file.recover",
"Recover file",
@@ -1374,14 +1388,36 @@ fn close(s: &mut Session, p: &Value) -> Result<Value> {
return Err(EngineError::Disabled("file.close".into(), "the document has unsaved changes (pass force: true to discard)".into()));
}
let uid = ds.uid;
let active_uid = s.docs.get(s.active).map(|d| d.uid);
s.docs.remove(i);
if s.active >= s.docs.len() {
s.active = s.docs.len().saturating_sub(1);
}
// Removing a tab before the active one shifts its index; keep the same document selected.
s.active = active_uid.and_then(|a| s.docs.iter().position(|d| d.uid == a)).unwrap_or(i.min(s.docs.len().saturating_sub(1)));
crate::branches::close_tabs(s, uid, None);
ok()
}
#[cfg(test)]
mod tab_order_tests {
use super::*;
#[test]
fn moving_and_closing_inactive_tabs_preserves_the_active_document() {
let mut session = Session::new();
for name in ["Two", "Three", "Four"] {
session.execute("file.new", &json!({"name": name})).unwrap();
}
session.execute("doc.switch", &json!({"index": 2})).unwrap();
let active_uid = session.docs[session.active].uid;
let moved_uid = session.docs[0].uid;
session.execute("file.moveTab", &json!({"from": 0, "to": 2})).unwrap();
assert_eq!(session.docs[2].uid, moved_uid);
assert_eq!(session.docs[session.active].uid, active_uid);
session.execute("file.close", &json!({"index": 0})).unwrap();
assert_eq!(session.docs[session.active].uid, active_uid);
assert!(session.execute("file.moveTab", &json!({"from": 0, "to": 99})).is_err());
}
}
/// Ctrl+Tab / Ctrl+Shift+Tab: the next or previous open document, wrapping around.
fn cycle_doc(s: &mut Session, dir: i64) -> Result<Value> {
let n = s.docs.len() as i64;
+1
View File
@@ -1849,6 +1849,7 @@ status = "draft — needs native review"
"file.exportLayers" = "Exportovat vrstvy"
"file.exportSvg" = "Exportovat výběr jako SVG"
"file.import" = "Importovat"
"file.moveTab" = "Přesunout kartu"
"file.new" = "Nový soubor návrhu"
"file.newFromTemplate" = "Nový ze šablony"
"file.open" = "Otevřít"
+1
View File
@@ -1795,6 +1795,7 @@ status = "draft — needs native review"
"file.exportLayers" = "Ebenen exportieren"
"file.exportSvg" = "Auswahl als SVG exportieren"
"file.import" = "Importieren"
"file.moveTab" = "Tab verschieben"
"file.new" = "Neue Designdatei"
"file.open" = "Öffnen"
"file.openRecent" = "Zuletzt verwendete öffnen"
+1
View File
@@ -1890,6 +1890,7 @@ status = "draft — needs native review"
"file.exportLayers" = "Exportar capas"
"file.exportSvg" = "Exportar selección como SVG"
"file.import" = "Importar"
"file.moveTab" = "Mover pestaña"
"file.new" = "Nuevo archivo de diseño"
"file.newFromTemplate" = "Nuevo desde plantilla"
"file.open" = "Abrir"
+1
View File
@@ -1891,6 +1891,7 @@ status = "draft — needs native review"
"file.exportLayers" = "Vie tasot"
"file.exportSvg" = "Vie valinta SVG-muodossa"
"file.import" = "Tuo"
"file.moveTab" = "Siirrä välilehti"
"file.new" = "Uusi suunnittelutiedosto"
"file.newFromTemplate" = "Uusi mallista"
"file.open" = "Avaa"
+1
View File
@@ -1879,6 +1879,7 @@ status = "draft — needs native review"
"file.exportLayers" = "Exporter les calques"
"file.exportSvg" = "Exporter la sélection en SVG"
"file.import" = "Importer"
"file.moveTab" = "Déplacer l’onglet"
"file.new" = "Nouveau fichier de design"
"file.newFromTemplate" = "Nouveau à partir d’un modèle"
"file.open" = "Ouvrir"
+1
View File
@@ -1853,6 +1853,7 @@ status = "draft — needs native review"
"file.exportLayers" = "Ekspor layer"
"file.exportSvg" = "Ekspor pilihan sebagai SVG"
"file.import" = "Impor"
"file.moveTab" = "Pindahkan tab"
"file.new" = "File desain baru"
"file.newFromTemplate" = "Baru dari templat"
"file.open" = "Buka"
+1
View File
@@ -1864,6 +1864,7 @@ status = "draft — needs native review"
"file.exportLayers" = "レイヤーを書き出し"
"file.exportSvg" = "選択範囲を SVG で書き出し"
"file.import" = "インポート"
"file.moveTab" = "タブを移動"
"file.new" = "新規デザインファイル"
"file.newFromTemplate" = "テンプレートから新規作成"
"file.open" = "開く"
+1
View File
@@ -1786,6 +1786,7 @@ status = "draft — needs native review"
"file.exportLayers" = "레이어 내보내기"
"file.exportSvg" = "선택 항목을 SVG로 내보내기"
"file.import" = "가져오기"
"file.moveTab" = "탭 이동"
"file.new" = "새 디자인 파일"
"file.open" = "열기"
"file.openRecent" = "최근 파일 열기"
+1
View File
@@ -1890,6 +1890,7 @@ status = "draft — needs native review"
"file.exportLayers" = "Lagen exporteren"
"file.exportSvg" = "Selectie exporteren als SVG"
"file.import" = "Importeren"
"file.moveTab" = "Tabblad verplaatsen"
"file.new" = "Nieuw ontwerpbestand"
"file.newFromTemplate" = "Nieuw vanuit sjabloon"
"file.open" = "Openen"
+1
View File
@@ -1785,6 +1785,7 @@ status = "draft — needs native review"
"file.exportLayers" = "Exportar camadas"
"file.exportSvg" = "Exportar seleção como SVG"
"file.import" = "Importar"
"file.moveTab" = "Mover aba"
"file.new" = "Novo arquivo de design"
"file.open" = "Abrir"
"file.openRecent" = "Abrir recente"
+1
View File
@@ -1855,6 +1855,7 @@ name = "Русский"
"file.exportLayers" = "Экспортировать слои"
"file.exportSvg" = "Экспортировать выделение в SVG"
"file.import" = "Импорт"
"file.moveTab" = "Переместить вкладку"
"file.new" = "Новый файл дизайна"
"file.newFromTemplate" = "Создать из шаблона"
"file.open" = "Открыть"
+1
View File
@@ -1872,6 +1872,7 @@ name = "Svenska"
"file.exportLayers" = "Exportera lager"
"file.exportSvg" = "Exportera som SVG"
"file.import" = "Importera"
"file.moveTab" = "Flytta flik"
"file.new" = "Nytt"
"file.newFromTemplate" = "Nytt från mall"
"file.open" = "Öppna"
+1
View File
@@ -1853,6 +1853,7 @@ name = "Türkçe"
"file.exportLayers" = "Katmanları dışa aktar"
"file.exportSvg" = "Seçimi SVG olarak dışa aktar"
"file.import" = "İçe aktar"
"file.moveTab" = "Sekmeyi taşı"
"file.new" = "Yeni tasarım dosyası"
"file.newFromTemplate" = "Şablondan yeni"
"file.open" = "Aç"
+1
View File
@@ -1787,6 +1787,7 @@ status = "draft — needs native review"
"file.exportLayers" = "导出图层"
"file.exportSvg" = "将所选项导出为 SVG"
"file.import" = "导入"
"file.moveTab" = "移动标签页"
"file.new" = "新建设计文件"
"file.open" = "打开"
"file.openRecent" = "打开最近的文件"