notepad: confirm before loading files over 5 MiB

closes #3574
This commit is contained in:
bbedward
2026-09-25 18:36:42 -04:00
parent 909c0055ea
commit 3b1b63c93f
6 changed files with 96 additions and 18 deletions
+1 -1
View File
@@ -83,7 +83,7 @@ require (
)
require (
github.com/AvengeMedia/dankgo v1.6.3-0.20260925183658-cbde42a10318
github.com/AvengeMedia/dankgo v1.6.3-0.20260925221540-1ea246498904
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/colorprofile v0.4.3 // indirect
+2 -2
View File
@@ -1,7 +1,7 @@
filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo=
filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc=
github.com/AvengeMedia/dankgo v1.6.3-0.20260925183658-cbde42a10318 h1:tVRgu+ENpVIYCzHe9PHJ3BcMoBDW8OYTqtgsjBwuT6o=
github.com/AvengeMedia/dankgo v1.6.3-0.20260925183658-cbde42a10318/go.mod h1:Fj+FTCumlv8YjKmdv75DREJuGmqU9EnGpBroZuCWc/k=
github.com/AvengeMedia/dankgo v1.6.3-0.20260925221540-1ea246498904 h1:s773vsx6JeQjPphXKq3AhMZgiWMDfhjuS5Bw3KvBJ3c=
github.com/AvengeMedia/dankgo v1.6.3-0.20260925221540-1ea246498904/go.mod h1:Fj+FTCumlv8YjKmdv75DREJuGmqU9EnGpBroZuCWc/k=
github.com/AvengeMedia/dgop v1.6.3-0.20260920163359-59c7d81ae3b9 h1:ssoiAng7ng500BgtZa1riJH6kKudQVM8Uk9a9kF7mDA=
github.com/AvengeMedia/dgop v1.6.3-0.20260920163359-59c7d81ae3b9/go.mod h1:8TFIP72NLxCbogF2hHU6sXj3RoTbHQW8beeCrisHs/Y=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
+1 -1
View File
@@ -111,7 +111,7 @@
inherit version;
pname = "dms-shell";
src = ./core;
vendorHash = "sha256-Yl/5wAQGWwk7BW3vkEWHJtZU8xmIBGqFu81i8/7cquc=";
vendorHash = "sha256-EPkg9jw2GcdrFTJeOv45P3+j85ytfpKJ08Q5nqX6ZKE=";
subPackages = [ "cmd/dms" ];
+51 -4
View File
@@ -8,6 +8,7 @@ import qs.Modals.Common
import qs.Modals.FileBrowser
import qs.Services
import qs.Widgets
import "../../Common/Format.js" as Format
Item {
id: root
@@ -244,14 +245,43 @@ Item {
}
}
function confirmLargeFile(path, size, onOpen, onCancel) {
largeFileConfirmLoader.active = true;
const confirm = largeFileConfirmLoader.item;
if (!confirm)
return;
root.confirmationDialogOpen = true;
confirm.showWithOptions({
"title": I18n.tr("Open large file?", "notepad prompt before loading a file over the size limit"),
"message": I18n.tr("%1 is %2 and may use a lot of memory.", "notepad large file prompt, file name then size").arg(path.split('/').pop()).arg(Format.formatBytes(size)),
"confirmText": I18n.tr("Open"),
"onConfirm": () => {
root.confirmationDialogOpen = false;
NotepadStorageService.approveLargeFile(path);
onOpen();
},
"onCancel": () => {
root.confirmationDialogOpen = false;
onCancel();
}
});
}
function performLoadFromFile(fileUrl) {
const filePath = fileUrl.toString().replace(/^file:\/\//, '');
const fileName = filePath.split('/').pop();
loadFileView.path = "";
loadFileView.path = filePath;
NotepadStorageService.readFileSize(filePath, size => {
if (NotepadStorageService.needsLargeFileConfirm(filePath, size)) {
root.confirmLargeFile(filePath, size, () => root.performLoadFromFile(fileUrl), () => {});
return;
}
if (loadFileView.waitForJob()) {
loadFileView.path = "";
loadFileView.path = filePath;
if (!loadFileView.waitForJob())
return;
Qt.callLater(() => {
var content = loadFileView.text();
if (currentTab && content !== undefined && content !== null) {
@@ -274,7 +304,7 @@ Item {
NotepadStorageService.clearConflict();
}
});
}
});
}
Item {
@@ -500,6 +530,14 @@ Item {
root.showConflictBanner(diskContent);
}
onLargeFileConfirmRequested: (tab, size) => {
if (!root.surfaceVisible)
return;
root.confirmLargeFile(tab.filePath, size, () => textEditor.loadCurrentTabContent(), () => {
root.performCloseTab(NotepadStorageService.tabs.findIndex(t => t.id === tab.id));
});
}
onAutoSaveRequested: root.autoSaveExternal()
}
}
@@ -643,6 +681,15 @@ Item {
}
}
LazyLoader {
id: largeFileConfirmLoader
active: false
ConfirmModal {
useOverlayLayer: true
}
}
LazyLoader {
id: confirmationDialogLoader
active: false
@@ -60,6 +60,7 @@ Column {
signal popoutRequested
signal dockRequested
signal conflictDetected(string diskContent)
signal largeFileConfirmRequested(var tab, real size)
signal autoSaveRequested
function hasUnsavedChanges() {
@@ -110,6 +111,14 @@ Column {
loadedTabId = requestedTabId;
contentLoaded = true;
syncContentToPlugin();
}, size => {
if (requestId !== loadRequestId || !currentTab || currentTab.id !== requestedTabId)
return;
applyingShared = true;
lastSavedContent = "";
textArea.text = "";
applyingShared = false;
root.largeFileConfirmRequested(currentTab, size);
});
}
@@ -1071,7 +1080,7 @@ Column {
FileView {
id: externalWatch
path: (!root.externalWatchPaused && currentTab && !currentTab.isTemporary && currentTab.filePath) ? currentTab.filePath : ""
path: (!root.externalWatchPaused && currentTab && !currentTab.isTemporary && currentTab.filePath && root.loadedTabId === currentTab.id) ? currentTab.filePath : ""
blockLoading: true
preload: true
watchChanges: true
+31 -9
View File
@@ -13,6 +13,8 @@ Singleton {
readonly property var log: Log.scoped("NotepadStorageService")
property int refCount: 0
readonly property int largeFileBytes: 5 * 1024 * 1024
property var approvedLargeFiles: ({})
readonly property string baseDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericStateLocation) + "/DankMaterialShell")
readonly property string filesDir: baseDir + "/notepad-files"
@@ -160,7 +162,7 @@ Singleton {
return null;
}
function loadTabContent(tabIndex, callback) {
function loadTabContent(tabIndex, callback, onLargeFile) {
if (tabIndex < 0 || tabIndex >= tabs.length) {
callback("");
return;
@@ -172,12 +174,12 @@ Singleton {
if (tabsBeingCreated[tab.id]) {
Qt.callLater(() => {
loadTabContent(tabIndex, callback);
loadTabContent(tabIndex, callback, onLargeFile);
});
return;
}
Proc.runCommand("", ["test", "-f", fullPath], (output, exitCode) => {
readFileSize(fullPath, size => {
var currentTab = root.getTabById(requestTabId);
var currentPath = currentTab ? (currentTab.isTemporary ? baseDir + "/" + currentTab.filePath : currentTab.filePath) : "";
@@ -186,18 +188,38 @@ Singleton {
return;
}
if (exitCode === 0) {
tabFileLoaderComponent.createObject(root, {
path: fullPath,
callback: callback
});
} else {
if (size < 0) {
log.warn("Tab file does not exist:", fullPath);
callback("");
return;
}
if (!currentTab.isTemporary && root.needsLargeFileConfirm(fullPath, size)) {
onLargeFile(size);
return;
}
tabFileLoaderComponent.createObject(root, {
path: fullPath,
callback: callback
});
});
}
function readFileSize(path, callback) {
Proc.runCommand("", ["sh", "-c", "test -f \"$1\" && wc -c < \"$1\"", "sh", path], (output, exitCode) => {
callback(exitCode === 0 ? parseInt(output) : -1);
});
}
function needsLargeFileConfirm(path, size) {
return size > largeFileBytes && !approvedLargeFiles[path];
}
function approveLargeFile(path) {
approvedLargeFiles[path] = true;
}
function saveTabContent(tabIndex, content) {
if (tabIndex < 0 || tabIndex >= tabs.length)
return;