From 71b1901ab00b9c5d6c4f4968374704a8c3c5d7db Mon Sep 17 00:00:00 2001 From: bbedward Date: Tue, 7 Jul 2026 11:05:14 -0400 Subject: [PATCH] notepad: add inline tab renaming and bump tab size --- quickshell/Common/SessionData.qml | 19 +- quickshell/Common/settings/SessionSpec.js | 2 + quickshell/DMSShellIPC.qml | 8 +- quickshell/Modules/Notepad/NotepadTabs.qml | 81 ++- quickshell/Services/NotepadStorageService.qml | 503 ++++++++---------- quickshell/Services/PopoutService.qml | 13 +- 6 files changed, 338 insertions(+), 288 deletions(-) diff --git a/quickshell/Common/SessionData.qml b/quickshell/Common/SessionData.qml index 536cbbd7d..12fb3477f 100644 --- a/quickshell/Common/SessionData.qml +++ b/quickshell/Common/SessionData.qml @@ -120,12 +120,18 @@ Singleton { function setMonitorScrollPosition(screenName, scrollX, scrollY) { var newPositions = Object.assign({}, monitorScrollPositions); - newPositions[screenName] = { scrollX: scrollX, scrollY: scrollY }; + newPositions[screenName] = { + scrollX: scrollX, + scrollY: scrollY + }; monitorScrollPositions = newPositions; } function getMonitorScrollPosition(screenName) { - return monitorScrollPositions[screenName] || { scrollX: 50, scrollY: 50 }; + return monitorScrollPositions[screenName] || { + scrollX: 50, + scrollY: 50 + }; } function clearMonitorScrollPosition(screenName) { @@ -209,6 +215,8 @@ Singleton { property string locale: "" property string timeLocale: "" + property string notepadLastMode: "" + property string launcherLastMode: "all" property string launcherLastFileSearchType: "all" property string launcherLastQuery: "" @@ -1216,6 +1224,13 @@ Singleton { I18n.useLocale(locale, locale.startsWith("en") ? "" : I18n.folder + "/" + locale + ".json"); } + function setNotepadLastMode(mode) { + if (notepadLastMode === mode) + return; + notepadLastMode = mode; + saveSettings(); + } + function setLauncherLastMode(mode) { launcherLastMode = mode; saveSettings(); diff --git a/quickshell/Common/settings/SessionSpec.js b/quickshell/Common/settings/SessionSpec.js index a0c72573a..c11bcf788 100644 --- a/quickshell/Common/settings/SessionSpec.js +++ b/quickshell/Common/settings/SessionSpec.js @@ -88,6 +88,8 @@ var SPEC = { locale: { def: "", onChange: "updateLocale" }, timeLocale: { def: "" }, + notepadLastMode: { def: "" }, + launcherLastMode: { def: "all" }, launcherLastFileSearchType: { def: "all" }, launcherLastQuery: { def: "" }, diff --git a/quickshell/DMSShellIPC.qml b/quickshell/DMSShellIPC.qml index 496942ee1..75aa6a04f 100644 --- a/quickshell/DMSShellIPC.qml +++ b/quickshell/DMSShellIPC.qml @@ -373,7 +373,7 @@ Item { } function open(): string { - if (SettingsData.notepadDefaultMode === "popout") { + if (PopoutService.notepadResolvedMode === "popout") { PopoutService.openNotepadPopout(); return "NOTEPAD_OPEN_SUCCESS"; } @@ -388,7 +388,7 @@ Item { function openFile(path: string): string { if (!path) return open(); - if (SettingsData.notepadDefaultMode === "popout") { + if (PopoutService.notepadResolvedMode === "popout") { PopoutService.openNotepadPopoutWithFile(path); return "NOTEPAD_OPEN_FILE_SUCCESS"; } @@ -402,7 +402,7 @@ Item { } function close(): string { - if (SettingsData.notepadDefaultMode === "popout") { + if (PopoutService.notepadResolvedMode === "popout") { PopoutService.notepadPopout?.hide(); return "NOTEPAD_CLOSE_SUCCESS"; } @@ -415,7 +415,7 @@ Item { } function toggle(): string { - if (SettingsData.notepadDefaultMode === "popout") { + if (PopoutService.notepadResolvedMode === "popout") { PopoutService.toggleNotepadPopout(); return "NOTEPAD_TOGGLE_SUCCESS"; } diff --git a/quickshell/Modules/Notepad/NotepadTabs.qml b/quickshell/Modules/Notepad/NotepadTabs.qml index 1ed0674e5..ab31977ba 100644 --- a/quickshell/Modules/Notepad/NotepadTabs.qml +++ b/quickshell/Modules/Notepad/NotepadTabs.qml @@ -13,12 +13,19 @@ Column { property int draggedIndex: -1 property int dropTargetIndex: -1 property bool suppressShiftAnimation: false - readonly property real tabItemSize: 128 + Theme.spacingXS + property int editingIndex: -1 + readonly property real tabItemSize: tabRow.dynamicTabWidth + Theme.spacingXS signal tabSwitched(int tabIndex) signal tabClosed(int tabIndex) signal newTabRequested + function commitRename(index, newTitle) { + if (index >= 0) + NotepadStorageService.renameTab(index, newTitle); + editingIndex = -1; + } + function hasUnsavedChangesForTab(tab) { if (!tab) return false; @@ -32,11 +39,19 @@ Column { spacing: Theme.spacingXS Row { + id: tabRow width: parent.width height: 36 spacing: Theme.spacingXS + readonly property real dynamicTabWidth: { + var count = Math.max(1, NotepadStorageService.tabs.length); + var raw = (tabScroll.width - (count - 1) * Theme.spacingXS) / count; + return Math.max(128, Math.min(300, raw)); + } + ScrollView { + id: tabScroll width: parent.width - newTabButton.width - Theme.spacingXS height: parent.height clip: true @@ -57,7 +72,8 @@ Column { readonly property bool isActive: NotepadStorageService.currentTabIndex === index readonly property bool isHovered: tabMouseArea.containsMouse && !closeMouseArea.containsMouse - readonly property real tabWidth: 128 + readonly property bool editing: root.editingIndex === index + readonly property real tabWidth: tabRow.dynamicTabWidth property bool longPressing: false property bool dragging: false property point dragStartPos: Qt.point(0, 0) @@ -138,6 +154,7 @@ Column { StyledText { id: tabText + visible: !delegateItem.editing width: parent.width - (tabCloseButton.visible ? tabCloseButton.width + Theme.spacingXS : 0) text: { var prefix = ""; @@ -155,13 +172,54 @@ Column { anchors.verticalCenter: parent.verticalCenter } + TextInput { + id: renameField + visible: delegateItem.editing + enabled: delegateItem.editing + width: parent.width + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: Theme.fontSizeSmall + font.weight: Font.Medium + color: Theme.primary + selectionColor: Theme.primary + selectedTextColor: Theme.background + selectByMouse: true + clip: true + + onEditingFinished: root.commitRename(index, text) + Keys.onEscapePressed: event => { + text = modelData.title || "Untitled"; + root.editingIndex = -1; + event.accepted = true; + } + + // A tab switch re-focuses the editor via Qt.callLater; the + // timer fires afterwards so the field keeps focus + selection. + Timer { + id: renameFocusTimer + interval: 20 + repeat: false + onTriggered: { + renameField.forceActiveFocus(); + renameField.selectAll(); + } + } + + onVisibleChanged: { + if (!visible) + return; + text = modelData.title || "Untitled"; + renameFocusTimer.restart(); + } + } + Rectangle { id: tabCloseButton width: 20 height: 20 radius: Theme.cornerRadius color: closeMouseArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0) - visible: NotepadStorageService.tabs.length > 1 + visible: NotepadStorageService.tabs.length > 1 && !delegateItem.editing anchors.verticalCenter: parent.verticalCenter DankIcon { @@ -195,11 +253,24 @@ Column { MouseArea { id: tabMouseArea anchors.fill: parent + enabled: !delegateItem.editing hoverEnabled: true preventStealing: dragging || longPressing cursorShape: dragging || longPressing ? Qt.ClosedHandCursor : Qt.PointingHandCursor acceptedButtons: Qt.LeftButton + onDoubleClicked: { + root.tabSwitched(index); + root.editingIndex = index; + } + + onExited: tabTooltip.hide() + + onContainsMouseChanged: { + if (containsMouse && tabText.truncated) + tabTooltip.show(modelData.title || "Untitled", delegateItem, 0, 0, "bottom"); + } + onPressed: mouse => { if (mouse.button === Qt.LeftButton && NotepadStorageService.tabs.length > 1) { delegateItem.dragStartPos = Qt.point(mouse.x, mouse.y); @@ -279,4 +350,8 @@ Column { onClicked: root.newTabRequested() } } + + DankTooltipV2 { + id: tabTooltip + } } diff --git a/quickshell/Services/NotepadStorageService.qml b/quickshell/Services/NotepadStorageService.qml index 50d78894d..dcd14fd20 100644 --- a/quickshell/Services/NotepadStorageService.qml +++ b/quickshell/Services/NotepadStorageService.qml @@ -29,45 +29,48 @@ Singleton { function setSessionBuffer(tabId, content, baseline) { if (tabId === undefined || tabId === null || tabId < 0) - return - var next = Object.assign({}, sessionBuffers) + return; + var next = Object.assign({}, sessionBuffers); if (content !== baseline) { - next[tabId] = { content: content, baseline: baseline } + next[tabId] = { + content: content, + baseline: baseline + }; } else { - delete next[tabId] + delete next[tabId]; } - sessionBuffers = next - sessionBufferRevision++ + sessionBuffers = next; + sessionBufferRevision++; } function getSessionBuffer(tabId) { - return sessionBuffers[tabId] + return sessionBuffers[tabId]; } function clearSessionBuffer(tabId) { if (sessionBuffers[tabId] === undefined) - return - var next = Object.assign({}, sessionBuffers) - delete next[tabId] - sessionBuffers = next - sessionBufferRevision++ + return; + var next = Object.assign({}, sessionBuffers); + delete next[tabId]; + sessionBuffers = next; + sessionBufferRevision++; } property var conflictTabId: -1 property string conflictDiskContent: "" function flagConflict(tabId, diskContent) { - conflictDiskContent = diskContent - conflictTabId = tabId + conflictDiskContent = diskContent; + conflictTabId = tabId; } function clearConflict() { - conflictTabId = -1 - conflictDiskContent = "" + conflictTabId = -1; + conflictDiskContent = ""; } Component.onCompleted: { - ensureDirectories() + ensureDirectories(); } FileView { @@ -78,64 +81,66 @@ Singleton { onLoaded: { try { - var data = JSON.parse(text()) - root.tabs = data.tabs || [] - root.currentTabIndex = data.currentTabIndex || 0 - root.metadataLoaded = true - root.validateTabs() - } catch(e) { - log.warn("Failed to parse notepad metadata:", e) - root.createDefaultTab() + var data = JSON.parse(text()); + root.tabs = data.tabs || []; + root.currentTabIndex = data.currentTabIndex || 0; + root.metadataLoaded = true; + root.validateTabs(); + } catch (e) { + log.warn("Failed to parse notepad metadata:", e); + root.createDefaultTab(); } } onLoadFailed: { - root.createDefaultTab() + root.createDefaultTab(); } } onRefCountChanged: { if (refCount === 1 && !metadataLoaded) { - metadataFile.path = "" - metadataFile.path = root.metadataPath + metadataFile.path = ""; + metadataFile.path = root.metadataPath; } } function ensureDirectories() { - mkdirProcess.running = true + Proc.runCommand("", ["mkdir", "-p", root.baseDir, root.filesDir], null); } function loadMetadata() { - metadataFile.path = "" - metadataFile.path = root.metadataPath + metadataFile.path = ""; + metadataFile.path = root.metadataPath; } function createDefaultTab() { - var id = Date.now() - var filePath = "notepad-files/untitled-" + id + ".txt" - var fullPath = baseDir + "/" + filePath + var id = Date.now(); + var filePath = "notepad-files/untitled-" + id + ".txt"; + var fullPath = baseDir + "/" + filePath; - var newTabsBeingCreated = Object.assign({}, tabsBeingCreated) - newTabsBeingCreated[id] = true - tabsBeingCreated = newTabsBeingCreated + var newTabsBeingCreated = Object.assign({}, tabsBeingCreated); + newTabsBeingCreated[id] = true; + tabsBeingCreated = newTabsBeingCreated; - root.createEmptyFile(fullPath, function() { - root.tabs = [{ - id: id, - title: I18n.tr("Untitled"), - filePath: filePath, - isTemporary: true, - lastModified: new Date().toISOString(), - cursorPosition: 0, - scrollPosition: 0 - }] - root.currentTabIndex = 0 + root.createEmptyFile(fullPath, function () { + root.tabs = [ + { + id: id, + title: I18n.tr("Untitled"), + filePath: filePath, + isTemporary: true, + lastModified: new Date().toISOString(), + cursorPosition: 0, + scrollPosition: 0 + } + ]; + root.currentTabIndex = 0; - var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated) - delete updatedTabsBeingCreated[id] - tabsBeingCreated = updatedTabsBeingCreated - root.saveMetadata() - }) + var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated); + delete updatedTabsBeingCreated[id]; + tabsBeingCreated = updatedTabsBeingCreated; + root.saveMetadata(); + }); } function saveMetadata() { @@ -143,82 +148,73 @@ Singleton { version: 1, currentTabIndex: currentTabIndex, tabs: tabs - } - metadataFile.setText(JSON.stringify(metadata, null, 2)) + }; + metadataFile.setText(JSON.stringify(metadata, null, 2)); } function getTabById(tabId) { for (var i = 0; i < tabs.length; i++) { if (tabs[i].id === tabId) - return tabs[i] + return tabs[i]; } - return null + return null; } function loadTabContent(tabIndex, callback) { if (tabIndex < 0 || tabIndex >= tabs.length) { - callback("") - return + callback(""); + return; } - var tab = tabs[tabIndex] - var requestTabId = tab.id - var fullPath = tab.isTemporary - ? baseDir + "/" + tab.filePath - : tab.filePath + var tab = tabs[tabIndex]; + var requestTabId = tab.id; + var fullPath = tab.isTemporary ? baseDir + "/" + tab.filePath : tab.filePath; if (tabsBeingCreated[tab.id]) { Qt.callLater(() => { - loadTabContent(tabIndex, callback) - }) - return + loadTabContent(tabIndex, callback); + }); + return; } - var fileChecker = fileExistsComponent.createObject(root, { - path: fullPath, - callback: (exists) => { - var currentTab = root.getTabById(requestTabId) - var currentPath = currentTab - ? (currentTab.isTemporary ? baseDir + "/" + currentTab.filePath : currentTab.filePath) - : "" + Proc.runCommand("", ["test", "-f", fullPath], (output, exitCode) => { + var currentTab = root.getTabById(requestTabId); + var currentPath = currentTab ? (currentTab.isTemporary ? baseDir + "/" + currentTab.filePath : currentTab.filePath) : ""; - if (!currentTab || currentPath !== fullPath) { - callback("") - return - } - - if (exists) { - var loader = tabFileLoaderComponent.createObject(root, { - path: fullPath, - callback: callback - }) - } else { - log.warn("Tab file does not exist:", fullPath) - callback("") - } + if (!currentTab || currentPath !== fullPath) { + callback(""); + return; } - }) + + if (exitCode === 0) { + tabFileLoaderComponent.createObject(root, { + path: fullPath, + callback: callback + }); + } else { + log.warn("Tab file does not exist:", fullPath); + callback(""); + } + }); } function saveTabContent(tabIndex, content) { - if (tabIndex < 0 || tabIndex >= tabs.length) return - - var tab = tabs[tabIndex] - var fullPath = tab.isTemporary - ? baseDir + "/" + tab.filePath - : tab.filePath + if (tabIndex < 0 || tabIndex >= tabs.length) + return; + var tab = tabs[tabIndex]; + var fullPath = tab.isTemporary ? baseDir + "/" + tab.filePath : tab.filePath; var saver = tabFileSaverComponent.createObject(root, { path: fullPath, content: content, tabIndex: tabIndex - }) + }); } function createNewTab() { - var id = Date.now() - var filePath = "notepad-files/untitled-" + id + ".txt" - var fullPath = baseDir + "/" + filePath + var id = Date.now(); + var filePath = "notepad-files/untitled-" + id + ".txt"; + var fullPath = baseDir + "/" + filePath; var newTab = { id: id, @@ -228,29 +224,29 @@ Singleton { lastModified: new Date().toISOString(), cursorPosition: 0, scrollPosition: 0 - } + }; - var newTabsBeingCreated = Object.assign({}, tabsBeingCreated) - newTabsBeingCreated[id] = true - tabsBeingCreated = newTabsBeingCreated - createEmptyFile(fullPath, function() { - var newTabs = tabs.slice() - newTabs.push(newTab) - tabs = newTabs - currentTabIndex = tabs.length - 1 + var newTabsBeingCreated = Object.assign({}, tabsBeingCreated); + newTabsBeingCreated[id] = true; + tabsBeingCreated = newTabsBeingCreated; + createEmptyFile(fullPath, function () { + var newTabs = tabs.slice(); + newTabs.push(newTab); + tabs = newTabs; + currentTabIndex = tabs.length - 1; - var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated) - delete updatedTabsBeingCreated[id] - tabsBeingCreated = updatedTabsBeingCreated - saveMetadata() - }) + var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated); + delete updatedTabsBeingCreated[id]; + tabsBeingCreated = updatedTabsBeingCreated; + saveMetadata(); + }); - return newTab + return newTab; } function createTabForFile(path) { - var id = Date.now() - var fileName = path.split('/').pop() + var id = Date.now(); + var fileName = path.split('/').pop(); var newTab = { id: id, @@ -260,34 +256,34 @@ Singleton { lastModified: new Date().toISOString(), cursorPosition: 0, scrollPosition: 0 - } + }; - var newTabs = tabs.slice() - newTabs.push(newTab) - tabs = newTabs - currentTabIndex = tabs.length - 1 - saveMetadata() + var newTabs = tabs.slice(); + newTabs.push(newTab); + tabs = newTabs; + currentTabIndex = tabs.length - 1; + saveMetadata(); - return newTab + return newTab; } function closeTab(tabIndex) { - if (tabIndex < 0 || tabIndex >= tabs.length) return - - var newTabs = tabs.slice() - var closedTabId = newTabs[tabIndex] ? newTabs[tabIndex].id : -1 - clearSessionBuffer(closedTabId) + if (tabIndex < 0 || tabIndex >= tabs.length) + return; + var newTabs = tabs.slice(); + var closedTabId = newTabs[tabIndex] ? newTabs[tabIndex].id : -1; + clearSessionBuffer(closedTabId); if (conflictTabId === closedTabId) - clearConflict() + clearConflict(); if (newTabs.length <= 1) { - var id = Date.now() - var filePath = "notepad-files/untitled-" + id + ".txt" + var id = Date.now(); + var filePath = "notepad-files/untitled-" + id + ".txt"; - var newTabsBeingCreated = Object.assign({}, tabsBeingCreated) - newTabsBeingCreated[id] = true - tabsBeingCreated = newTabsBeingCreated - createEmptyFile(baseDir + "/" + filePath, function() { + var newTabsBeingCreated = Object.assign({}, tabsBeingCreated); + newTabsBeingCreated[id] = true; + tabsBeingCreated = newTabsBeingCreated; + createEmptyFile(baseDir + "/" + filePath, function () { newTabs[0] = { id: id, title: I18n.tr("Untitled"), @@ -296,110 +292,129 @@ Singleton { lastModified: new Date().toISOString(), cursorPosition: 0, scrollPosition: 0 - } - currentTabIndex = 0 - tabs = newTabs + }; + currentTabIndex = 0; + tabs = newTabs; - var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated) - delete updatedTabsBeingCreated[id] - tabsBeingCreated = updatedTabsBeingCreated - saveMetadata() - }) - return + var updatedTabsBeingCreated = Object.assign({}, tabsBeingCreated); + delete updatedTabsBeingCreated[id]; + tabsBeingCreated = updatedTabsBeingCreated; + saveMetadata(); + }); + return; } else { - var tabToDelete = newTabs[tabIndex] + var tabToDelete = newTabs[tabIndex]; if (tabToDelete && tabToDelete.isTemporary) { - deleteFile(baseDir + "/" + tabToDelete.filePath) + deleteFile(baseDir + "/" + tabToDelete.filePath); } - newTabs.splice(tabIndex, 1) + newTabs.splice(tabIndex, 1); if (currentTabIndex >= newTabs.length) { - currentTabIndex = newTabs.length - 1 + currentTabIndex = newTabs.length - 1; } else if (currentTabIndex > tabIndex) { - currentTabIndex -= 1 + currentTabIndex -= 1; } } - tabs = newTabs - saveMetadata() - + tabs = newTabs; + saveMetadata(); } function switchToTab(tabIndex) { - if (tabIndex < 0 || tabIndex >= tabs.length) return - - currentTabIndex = tabIndex - saveMetadata() + if (tabIndex < 0 || tabIndex >= tabs.length) + return; + currentTabIndex = tabIndex; + saveMetadata(); } function reorderTab(fromIndex, toIndex) { if (fromIndex < 0 || fromIndex >= tabs.length || toIndex < 0 || toIndex >= tabs.length) - return + return; if (fromIndex === toIndex) - return - - var newTabs = tabs.slice() - var moved = newTabs.splice(fromIndex, 1)[0] - newTabs.splice(toIndex, 0, moved) - tabs = newTabs + return; + var newTabs = tabs.slice(); + var moved = newTabs.splice(fromIndex, 1)[0]; + newTabs.splice(toIndex, 0, moved); + tabs = newTabs; if (currentTabIndex === fromIndex) { - currentTabIndex = toIndex + currentTabIndex = toIndex; } else if (fromIndex < currentTabIndex && toIndex >= currentTabIndex) { - currentTabIndex-- + currentTabIndex--; } else if (fromIndex > currentTabIndex && toIndex <= currentTabIndex) { - currentTabIndex++ + currentTabIndex++; } - saveMetadata() + saveMetadata(); } function saveTabAs(tabIndex, userPath) { - if (tabIndex < 0 || tabIndex >= tabs.length) return - - var tab = tabs[tabIndex] - var fileName = userPath.split('/').pop() + if (tabIndex < 0 || tabIndex >= tabs.length) + return; + var tab = tabs[tabIndex]; + var fileName = userPath.split('/').pop(); if (tab.isTemporary) { - var tempPath = baseDir + "/" + tab.filePath - copyFile(tempPath, userPath) - deleteFile(tempPath) + var tempPath = baseDir + "/" + tab.filePath; + copyFile(tempPath, userPath); + deleteFile(tempPath); } - var newTabs = tabs.slice() + var newTabs = tabs.slice(); newTabs[tabIndex] = Object.assign({}, tab, { title: fileName, filePath: userPath, isTemporary: false, lastModified: new Date().toISOString() - }) - tabs = newTabs - saveMetadata() + }); + tabs = newTabs; + saveMetadata(); + } + function renameTab(tabIndex, newTitle) { + if (tabIndex < 0 || tabIndex >= tabs.length) + return; + var trimmed = (newTitle || "").trim(); + var tab = tabs[tabIndex]; + if (trimmed.length === 0 || trimmed === tab.title) + return; + if (tab.isTemporary) { + updateTabMetadata(tabIndex, { + title: trimmed + }); + return; + } + + var dir = tab.filePath.substring(0, tab.filePath.lastIndexOf('/') + 1); + var newPath = dir + trimmed; + moveFile(tab.filePath, newPath); + updateTabMetadata(tabIndex, { + title: trimmed, + filePath: newPath + }); } function updateTabMetadata(tabIndex, properties) { - if (tabIndex < 0 || tabIndex >= tabs.length) return - - var newTabs = tabs.slice() - var updatedTab = Object.assign({}, newTabs[tabIndex], properties) - updatedTab.lastModified = new Date().toISOString() - newTabs[tabIndex] = updatedTab - tabs = newTabs - saveMetadata() - + if (tabIndex < 0 || tabIndex >= tabs.length) + return; + var newTabs = tabs.slice(); + var updatedTab = Object.assign({}, newTabs[tabIndex], properties); + updatedTab.lastModified = new Date().toISOString(); + newTabs[tabIndex] = updatedTab; + tabs = newTabs; + saveMetadata(); } function validateTabs() { - var validTabs = [] + var validTabs = []; for (var i = 0; i < tabs.length; i++) { - var tab = tabs[i] - validTabs.push(tab) + var tab = tabs[i]; + validTabs.push(tab); } - tabs = validTabs + tabs = validTabs; if (tabs.length === 0) { - root.createDefaultTab() + root.createDefaultTab(); } } @@ -411,29 +426,13 @@ Singleton { preload: true onLoaded: { - callback(text()) - destroy() + callback(text()); + destroy(); } onLoadFailed: { - callback("") - destroy() - } - } - } - - Component { - id: fileExistsComponent - Process { - property string path - property var callback - command: ["test", "-f", path] - - Component.onCompleted: running = true - - onExited: (exitCode) => { - callback(exitCode === 0) - destroy() + callback(""); + destroy(); } } } @@ -452,94 +451,46 @@ Singleton { onSaved: { if (tabIndex >= 0) { - root.updateTabMetadata(tabIndex, {}) + root.updateTabMetadata(tabIndex, {}); } if (creationCallback) { - creationCallback() + creationCallback(); } - destroy() + destroy(); } onSaveFailed: { - log.error("Failed to save tab content") + log.error("Failed to save tab content"); if (creationCallback) { - creationCallback() + creationCallback(); } - destroy() + destroy(); } } } function createEmptyFile(path, callback) { - var cleanPath = decodeURI(path.toString()) + var cleanPath = decodeURI(path.toString()); if (!cleanPath.startsWith("/")) { - cleanPath = baseDir + "/" + cleanPath + cleanPath = baseDir + "/" + cleanPath; } - var creator = fileCreatorComponent.createObject(root, { - filePath: cleanPath, - creationCallback: callback - }) + Proc.runCommand("", ["touch", cleanPath], (output, exitCode) => { + if (callback) + callback(); + }); } function copyFile(source, destination) { - copyProcess.source = source - copyProcess.destination = destination - copyProcess.running = true + Proc.runCommand("", ["cp", source, destination], null); } function deleteFile(path) { - deleteProcess.filePath = path - deleteProcess.running = true + Proc.runCommand("", ["rm", "-f", path], null); } - Component { - id: fileCreatorComponent - QtObject { - property string filePath - property var creationCallback - - Component.onCompleted: { - var touchProcess = touchProcessComponent.createObject(this, { - filePath: filePath, - callback: creationCallback - }) - } - } - } - - Component { - id: touchProcessComponent - Process { - property string filePath - property var callback - command: ["touch", filePath] - - Component.onCompleted: running = true - - onExited: (exitCode) => { - if (callback) callback() - destroy() - } - } - } - - Process { - id: copyProcess - property string source - property string destination - command: ["cp", source, destination] - } - - Process { - id: deleteProcess - property string filePath - command: ["rm", "-f", filePath] - } - - Process { - id: mkdirProcess - command: ["mkdir", "-p", root.baseDir, root.filesDir] + function moveFile(source, destination) { + Proc.runCommand("", ["mv", source, destination], null); } } diff --git a/quickshell/Services/PopoutService.qml b/quickshell/Services/PopoutService.qml index 5b9cb4d01..93aa386d9 100644 --- a/quickshell/Services/PopoutService.qml +++ b/quickshell/Services/PopoutService.qml @@ -864,7 +864,12 @@ Singleton { return notepadSlideouts[0]; } + // Remembered presentation wins over the configured default until the user + // changes the default in settings (handled below). + readonly property string notepadResolvedMode: SessionData.notepadLastMode || SettingsData.notepadDefaultMode + function openNotepadSlideout() { + SessionData.setNotepadLastMode("slideout"); notepadPopout?.hide(); if (notepadSlideouts.length > 0) { notepadSlideoutForFocusedScreen()?.show(); @@ -875,6 +880,7 @@ Singleton { Connections { target: SettingsData function onNotepadDefaultModeChanged() { + SessionData.setNotepadLastMode(SettingsData.notepadDefaultMode); if (SettingsData.notepadDefaultMode === "popout") { var hadSlideout = false; for (var i = 0; i < root.notepadSlideouts.length; i++) { @@ -893,7 +899,7 @@ Singleton { } function openNotepad() { - if (SettingsData.notepadDefaultMode === "popout") { + if (notepadResolvedMode === "popout") { openNotepadPopout(); return; } @@ -901,7 +907,7 @@ Singleton { } function closeNotepad() { - if (SettingsData.notepadDefaultMode === "popout") { + if (notepadResolvedMode === "popout") { notepadPopout?.hide(); return; } @@ -911,7 +917,7 @@ Singleton { } function toggleNotepad() { - if (SettingsData.notepadDefaultMode === "popout") { + if (notepadResolvedMode === "popout") { toggleNotepadPopout(); return; } @@ -926,6 +932,7 @@ Singleton { property string _notepadPendingOpenFilePath: "" function openNotepadPopout() { + SessionData.setNotepadLastMode("popout"); closeNotepadSlideouts(); if (notepadPopout) { notepadPopout.show();