mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-05 01:09:40 +00:00
Improve Linux clipboard support and file handling (#872)
This commit is contained in:
1 parent
f666760415
commit
8fa0c4db01
16 files changed
+343
-166
No files matched your search
@@ -1,3 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
using AIStudio.Tools.Rust;
|
||||
|
||||
namespace AIStudio.Tools.Services;
|
||||
@@ -6,56 +8,90 @@ public sealed partial class RustService
|
||||
{
|
||||
public async Task<DirectorySelectionResponse> SelectDirectory(string title, string? initialDirectory = null)
|
||||
{
|
||||
var encodedTitle = Uri.EscapeDataString(title);
|
||||
var result = initialDirectory is null
|
||||
? await this.http.PostAsync($"/select/directory?title={encodedTitle}", null)
|
||||
: await this.http.PostAsJsonAsync($"/select/directory?title={encodedTitle}", new PreviousDirectory(initialDirectory), this.jsonRustSerializerOptions);
|
||||
|
||||
if (!result.IsSuccessStatusCode)
|
||||
return await this.RunFileDialog(
|
||||
"select directory",
|
||||
async () =>
|
||||
{
|
||||
var encodedTitle = Uri.EscapeDataString(title);
|
||||
var result = initialDirectory is null
|
||||
? await this.http.PostAsync($"/select/directory?title={encodedTitle}", null)
|
||||
: await this.http.PostAsJsonAsync($"/select/directory?title={encodedTitle}", new PreviousDirectory(initialDirectory), this.jsonRustSerializerOptions);
|
||||
|
||||
if (result.IsSuccessStatusCode)
|
||||
return await result.Content.ReadFromJsonAsync<DirectorySelectionResponse>(this.jsonRustSerializerOptions);
|
||||
|
||||
this.logger!.LogError("Failed to select a directory: '{StatusCode}'", result.StatusCode);
|
||||
return new DirectorySelectionResponse(true, string.Empty);
|
||||
},
|
||||
new DirectorySelectionResponse(true, string.Empty));
|
||||
}
|
||||
|
||||
private async Task<T> RunFileDialog<T>(string operation, Func<Task<T>> showDialog, T cancelledResult)
|
||||
{
|
||||
if (!await this.fileDialogLock.WaitAsync(0))
|
||||
{
|
||||
this.logger!.LogError($"Failed to select a directory: '{result.StatusCode}'");
|
||||
return new DirectorySelectionResponse(true, string.Empty);
|
||||
this.logger!.LogInformation("Ignored duplicate file dialog request for '{Operation}'.", operation);
|
||||
return cancelledResult;
|
||||
}
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
this.logger!.LogInformation("Opening file dialog for '{Operation}'.", operation);
|
||||
try
|
||||
{
|
||||
return await showDialog();
|
||||
}
|
||||
finally
|
||||
{
|
||||
stopwatch.Stop();
|
||||
this.fileDialogLock.Release();
|
||||
this.logger!.LogInformation("File dialog for '{Operation}' completed after {ElapsedMilliseconds} ms.", operation, stopwatch.ElapsedMilliseconds);
|
||||
}
|
||||
|
||||
return await result.Content.ReadFromJsonAsync<DirectorySelectionResponse>(this.jsonRustSerializerOptions);
|
||||
}
|
||||
|
||||
public async Task<FileSelectionResponse> SelectFile(string title, FileTypeFilter[]? filter = null, string? initialFile = null)
|
||||
{
|
||||
var payload = new SelectFileOptions
|
||||
{
|
||||
Title = title,
|
||||
PreviousFile = initialFile is null ? null : new (initialFile),
|
||||
Filter = FileTypes.AsOneFileType(filter)
|
||||
};
|
||||
return await this.RunFileDialog(
|
||||
"select file",
|
||||
async () =>
|
||||
{
|
||||
var payload = new SelectFileOptions
|
||||
{
|
||||
Title = title,
|
||||
PreviousFile = initialFile is null ? null : new (initialFile),
|
||||
Filter = FileTypes.AsOneFileType(filter)
|
||||
};
|
||||
|
||||
var result = await this.http.PostAsJsonAsync("/select/file", payload, this.jsonRustSerializerOptions);
|
||||
if (!result.IsSuccessStatusCode)
|
||||
{
|
||||
this.logger!.LogError($"Failed to select a file: '{result.StatusCode}'");
|
||||
return new FileSelectionResponse(true, string.Empty);
|
||||
}
|
||||
var result = await this.http.PostAsJsonAsync("/select/file", payload, this.jsonRustSerializerOptions);
|
||||
if (result.IsSuccessStatusCode)
|
||||
return await result.Content.ReadFromJsonAsync<FileSelectionResponse>(this.jsonRustSerializerOptions);
|
||||
|
||||
return await result.Content.ReadFromJsonAsync<FileSelectionResponse>(this.jsonRustSerializerOptions);
|
||||
this.logger!.LogError("Failed to select a file: '{StatusCode}'", result.StatusCode);
|
||||
return new FileSelectionResponse(true, string.Empty);
|
||||
},
|
||||
new FileSelectionResponse(true, string.Empty));
|
||||
}
|
||||
|
||||
public async Task<FilesSelectionResponse> SelectFiles(string title, FileTypeFilter[]? filter = null, string? initialFile = null)
|
||||
{
|
||||
var payload = new SelectFileOptions
|
||||
{
|
||||
Title = title,
|
||||
PreviousFile = initialFile is null ? null : new (initialFile),
|
||||
Filter = FileTypes.AsOneFileType(filter)
|
||||
};
|
||||
return await this.RunFileDialog(
|
||||
"select files",
|
||||
async () =>
|
||||
{
|
||||
var payload = new SelectFileOptions
|
||||
{
|
||||
Title = title,
|
||||
PreviousFile = initialFile is null ? null : new (initialFile),
|
||||
Filter = FileTypes.AsOneFileType(filter)
|
||||
};
|
||||
|
||||
var result = await this.http.PostAsJsonAsync("/select/files", payload, this.jsonRustSerializerOptions);
|
||||
if (!result.IsSuccessStatusCode)
|
||||
{
|
||||
this.logger!.LogError($"Failed to select files: '{result.StatusCode}'");
|
||||
return new FilesSelectionResponse(true, Array.Empty<string>());
|
||||
}
|
||||
var result = await this.http.PostAsJsonAsync("/select/files", payload, this.jsonRustSerializerOptions);
|
||||
if (result.IsSuccessStatusCode)
|
||||
return await result.Content.ReadFromJsonAsync<FilesSelectionResponse>(this.jsonRustSerializerOptions);
|
||||
|
||||
return await result.Content.ReadFromJsonAsync<FilesSelectionResponse>(this.jsonRustSerializerOptions);
|
||||
this.logger!.LogError("Failed to select files: '{StatusCode}'", result.StatusCode);
|
||||
return new FilesSelectionResponse(true, Array.Empty<string>());
|
||||
},
|
||||
new FilesSelectionResponse(true, Array.Empty<string>()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -68,21 +104,25 @@ public sealed partial class RustService
|
||||
/// operation and whether the select operation was successful.</returns>
|
||||
public async Task<FileSaveResponse> SaveFile(string title, FileTypeFilter[]? filter = null, string? initialFile = null)
|
||||
{
|
||||
var payload = new SaveFileOptions
|
||||
{
|
||||
Title = title,
|
||||
PreviousFile = initialFile is null ? null : new (initialFile),
|
||||
Filter = FileTypes.AsOneFileType(filter)
|
||||
};
|
||||
|
||||
var result = await this.http.PostAsJsonAsync("/save/file", payload, this.jsonRustSerializerOptions);
|
||||
if (!result.IsSuccessStatusCode)
|
||||
{
|
||||
this.logger!.LogError($"Failed to select a file for writing operation '{result.StatusCode}'");
|
||||
return new FileSaveResponse(true, string.Empty);
|
||||
}
|
||||
|
||||
return await result.Content.ReadFromJsonAsync<FileSaveResponse>(this.jsonRustSerializerOptions);
|
||||
return await this.RunFileDialog(
|
||||
"save file",
|
||||
async () =>
|
||||
{
|
||||
var payload = new SaveFileOptions
|
||||
{
|
||||
Title = title,
|
||||
PreviousFile = initialFile is null ? null : new (initialFile),
|
||||
Filter = FileTypes.AsOneFileType(filter)
|
||||
};
|
||||
|
||||
var result = await this.http.PostAsJsonAsync("/save/file", payload, this.jsonRustSerializerOptions);
|
||||
if (result.IsSuccessStatusCode)
|
||||
return await result.Content.ReadFromJsonAsync<FileSaveResponse>(this.jsonRustSerializerOptions);
|
||||
|
||||
this.logger!.LogError("Failed to select a file for writing operation: '{StatusCode}'", result.StatusCode);
|
||||
return new FileSaveResponse(true, string.Empty);
|
||||
},
|
||||
new FileSaveResponse(true, string.Empty));
|
||||
}
|
||||
|
||||
public async Task<OpenPathResponse> TryOpenPathInRuntimeFileManager(string path)
|
||||
|
||||
Reference in new issue
Block a user