Cleanup
Some checks are pending
Spell checking / Spell checking (push) Waiting to run
Spell checking / Report (Push) (push) Blocked by required conditions
Spell checking / Report (PR) (push) Blocked by required conditions
Spell checking / Update PR (push) Waiting to run

This commit is contained in:
Ani 2024-11-10 22:23:58 +01:00
parent 50153b0cce
commit 75a31da666
16 changed files with 65 additions and 127 deletions

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Diagnostics.Tracing;
using System.Linq;
using System.Text.Json;
using AdvancedPaste.Telemetry;
using Microsoft.PowerToys.Telemetry;

View File

@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage.Streams;

View File

@ -5,6 +5,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using ManagedCommon;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage.Streams;

View File

@ -93,7 +93,8 @@ internal static class DataPackageHelpers
return availableFormats == ClipboardFormat.Text ? !string.IsNullOrEmpty(await dataPackageView.GetTextAsync()) : availableFormats != ClipboardFormat.None;
}
internal static async Task<string> GetTextOrEmptyAsync(this DataPackageView dataPackageView) => dataPackageView.Contains(StandardDataFormats.Text) ? await dataPackageView.GetTextAsync() : string.Empty;
internal static async Task<string> GetTextOrEmptyAsync(this DataPackageView dataPackageView) =>
dataPackageView.Contains(StandardDataFormats.Text) ? await dataPackageView.GetTextAsync() : string.Empty;
internal static async Task<string> GetTextOrHtmlTextAsync(this DataPackageView dataPackageView)
{

View File

@ -33,30 +33,23 @@ namespace AdvancedPaste.Helpers
private static readonly Regex CsvRemoveStartAndEndQuotationMarksRegex = new Regex(@"^""(?=(""{2})+)|(?<=(""{2})+)""$");
private static readonly Regex CsvReplaceDoubleQuotationMarksRegex = new Regex(@"""{2}");
internal static string ToJsonFromXmlOrCsv(DataPackageView clipboardData)
internal static async Task<string> ToJsonFromXmlOrCsvAsync(DataPackageView clipboardData)
{
Logger.LogTrace();
if (clipboardData == null || !clipboardData.Contains(StandardDataFormats.Text))
if (!clipboardData.Contains(StandardDataFormats.Text))
{
Logger.LogWarning("Clipboard does not contain text data");
return string.Empty;
}
#pragma warning disable VSTHRD002 // Avoid problematic synchronous waits
string text = Task.Run(async () =>
{
string plainText = await clipboardData.GetTextAsync() as string;
return plainText;
}).Result;
#pragma warning restore VSTHRD002 // Avoid problematic synchronous waits
var text = await clipboardData.GetTextAsync();
string jsonText = string.Empty;
// Try convert XML
try
{
XmlDocument doc = new XmlDocument();
XmlDocument doc = new();
doc.LoadXml(text);
Logger.LogDebug("Converted from XML.");
jsonText = JsonConvert.SerializeXmlNode(doc, Newtonsoft.Json.Formatting.Indented);

View File

@ -15,67 +15,15 @@ namespace AdvancedPaste.Helpers
{
internal static class MarkdownHelper
{
public static string ToMarkdown(DataPackageView clipboardData)
public static async Task<string> ToMarkdownAsync(DataPackageView clipboardData)
{
Logger.LogTrace();
if (clipboardData == null)
{
Logger.LogWarning("Clipboard does not contain data");
var data = clipboardData.Contains(StandardDataFormats.Html) ? await clipboardData.GetHtmlFormatAsync()
: clipboardData.Contains(StandardDataFormats.Text) ? await clipboardData.GetTextAsync()
: string.Empty;
return string.Empty;
}
string data = string.Empty;
if (clipboardData.Contains(StandardDataFormats.Html))
{
data = Task.Run(async () =>
{
string data = await clipboardData.GetHtmlFormatAsync() as string;
return data;
}).Result;
}
else if (clipboardData.Contains(StandardDataFormats.Text))
{
data = Task.Run(async () =>
{
string plainText = await clipboardData.GetTextAsync() as string;
return plainText;
}).Result;
}
if (!string.IsNullOrEmpty(data))
{
string cleanedHtml = CleanHtml(data);
return ConvertHtmlToMarkdown(cleanedHtml);
}
return string.Empty;
}
public static string PasteAsPlainTextFromClipboard(DataPackageView clipboardData)
{
Logger.LogTrace();
if (clipboardData != null)
{
if (!clipboardData.Contains(StandardDataFormats.Text))
{
Logger.LogWarning("Clipboard does not contain text data");
return string.Empty;
}
return Task.Run(async () =>
{
string plainText = await clipboardData.GetTextAsync() as string;
return plainText;
}).Result;
}
return string.Empty;
return string.IsNullOrEmpty(data) ? string.Empty : ConvertHtmlToMarkdown(CleanHtml(data));
}
private static string CleanHtml(string html)

View File

@ -5,6 +5,7 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Windows.Globalization;
using Windows.Graphics.Imaging;
using Windows.Media.Ocr;

View File

@ -21,9 +21,9 @@ public static class TransformHelpers
{
return format switch
{
PasteFormats.PlainText => ToPlainText(clipboardData),
PasteFormats.Markdown => ToMarkdown(clipboardData),
PasteFormats.Json => ToJson(clipboardData),
PasteFormats.PlainText => await ToPlainTextAsync(clipboardData),
PasteFormats.Markdown => await ToMarkdownAsync(clipboardData),
PasteFormats.Json => await ToJsonAsync(clipboardData),
PasteFormats.ImageToText => await ImageToTextAsync(clipboardData),
PasteFormats.PasteAsTxtFile => await ToTxtFileAsync(clipboardData),
PasteFormats.PasteAsPngFile => await ToPngFileAsync(clipboardData),
@ -34,22 +34,22 @@ public static class TransformHelpers
};
}
private static DataPackage ToPlainText(DataPackageView clipboardData)
private static async Task<DataPackage> ToPlainTextAsync(DataPackageView clipboardData)
{
Logger.LogTrace();
return CreateDataPackageFromText(MarkdownHelper.PasteAsPlainTextFromClipboard(clipboardData));
return CreateDataPackageFromText(await clipboardData.GetTextOrEmptyAsync());
}
private static DataPackage ToMarkdown(DataPackageView clipboardData)
private static async Task<DataPackage> ToMarkdownAsync(DataPackageView clipboardData)
{
Logger.LogTrace();
return CreateDataPackageFromText(MarkdownHelper.ToMarkdown(clipboardData));
return CreateDataPackageFromText(await MarkdownHelper.ToMarkdownAsync(clipboardData));
}
private static DataPackage ToJson(DataPackageView clipboardData)
private static async Task<DataPackage> ToJsonAsync(DataPackageView clipboardData)
{
Logger.LogTrace();
return CreateDataPackageFromText(JsonHelper.ToJsonFromXmlOrCsv(clipboardData));
return CreateDataPackageFromText(await JsonHelper.ToJsonFromXmlOrCsvAsync(clipboardData));
}
private static async Task<DataPackage> ImageToTextAsync(DataPackageView clipboardData)

View File

@ -14,5 +14,5 @@ public enum ClipboardFormat
Html = 1 << 1,
Audio = 1 << 2,
Image = 1 << 3,
File = 1 << 4,
File = 1 << 4, // output only for now
}

View File

@ -62,5 +62,8 @@ public sealed class PasteFormat
public string ShortcutText { get; set; } = string.Empty;
public bool SupportsClipboardFormats(ClipboardFormat clipboardFormats) => (clipboardFormats & Metadata.SupportedClipboardFormats) != ClipboardFormat.None;
public static bool SupportsClipboardFormats(PasteFormats format, ClipboardFormat clipboardFormats)
=> (clipboardFormats & MetadataDict[format].SupportedClipboardFormats) != ClipboardFormat.None;
public bool SupportsClipboardFormats(ClipboardFormat clipboardFormats) => SupportsClipboardFormats(Format, clipboardFormats);
}

View File

@ -14,7 +14,8 @@ public enum PasteFormats
IconGlyph = "\uE8E9",
RequiresAIService = false,
CanPreview = false,
SupportedClipboardFormats = ClipboardFormat.Text)]
SupportedClipboardFormats = ClipboardFormat.Text,
KernelFunctionDescription = "Takes clipboard text and returns it as it is.")]
PlainText,
[PasteFormatMetadata(

View File

@ -18,6 +18,11 @@ using Microsoft.PowerToys.Settings.UI.Library;
namespace AdvancedPaste.Services;
/// <summary>
/// Implements <see cref="IKernelQueryCacheService"/> by only caching queries with prompts
/// that correspond to the user's custom actions or to the localized names of bundled actions.
/// This avoids potential privacy issues and prevents the cache from getting too large.
/// </summary>
public sealed class CustomActionKernelQueryCacheService : IKernelQueryCacheService
{
private const string PersistedCacheFileName = "kernelQueryCache.json";
@ -39,7 +44,7 @@ public sealed class CustomActionKernelQueryCacheService : IKernelQueryCacheServi
_userSettings.Changed += OnUserSettingsChanged;
RefreshCacheablePrompts();
UpdateCacheablePrompts();
_memoryCache = LoadPersistedCacheItems().Where(pair => pair.CacheKey != null)
.GroupBy(pair => pair.CacheKey, pair => pair.CacheValue)
@ -92,7 +97,7 @@ public sealed class CustomActionKernelQueryCacheService : IKernelQueryCacheServi
private async void OnUserSettingsChanged(object sender, EventArgs e)
{
RefreshCacheablePrompts();
UpdateCacheablePrompts();
if (RemoveInapplicableCacheKeys())
{
@ -100,7 +105,7 @@ public sealed class CustomActionKernelQueryCacheService : IKernelQueryCacheServi
}
}
private void RefreshCacheablePrompts()
private void UpdateCacheablePrompts()
{
var localizedActionNames = from pair in PasteFormat.MetadataDict
let format = pair.Key
@ -112,7 +117,6 @@ public sealed class CustomActionKernelQueryCacheService : IKernelQueryCacheServi
var customActionPrompts = from customAction in _userSettings.CustomActions
select customAction.Prompt;
// Only cache queries with these prompts to prevent the cache from getting too large and to avoid potential privacy issues.
_cacheablePrompts.Clear();
_cacheablePrompts.UnionWith(localizedActionNames.Concat(customActionPrompts));
}

View File

@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Threading.Tasks;
using Windows.ApplicationModel.DataTransfer;
namespace AdvancedPaste.Services;

View File

@ -30,7 +30,7 @@ public sealed class PasteFormatExecutor(IKernelService kernelService, ICustomTex
var clipboardData = Clipboard.GetContent();
// Run on thread-pool; even though we use Async routines consistently, some actions still occasionally take a long time without yielding.
// Run on thread-pool; although we use Async routines consistently, some actions still occasionally take a long time without yielding.
return await Task.Run(async () =>
pasteFormat.Format switch
{

View File

@ -79,7 +79,7 @@ namespace AdvancedPaste.ViewModels
public bool ClipboardHasData => AvailableClipboardFormats != ClipboardFormat.None;
public bool ClipboardHasDataForCustomAI => (AvailableClipboardFormats & PasteFormat.MetadataDict[CustomAIFormat].SupportedClipboardFormats) != ClipboardFormat.None;
public bool ClipboardHasDataForCustomAI => PasteFormat.SupportsClipboardFormats(CustomAIFormat, AvailableClipboardFormats);
private PasteFormats CustomAIFormat => _userSettings.IsAdvancedAIEnabled ? PasteFormats.KernelQuery : PasteFormats.CustomTextTransformation;
@ -166,7 +166,7 @@ namespace AdvancedPaste.ViewModels
private PasteFormat CreateStandardPasteFormat(PasteFormats format) =>
PasteFormat.CreateStandardFormat(format, AvailableClipboardFormats, IsCustomAIServiceEnabled, ResourceLoaderInstance.ResourceLoader.GetString);
private PasteFormat CreateAIServiceFormat(string name, string prompt, bool isSavedQuery) =>
private PasteFormat CreateCustomAIPasteFormat(string name, string prompt, bool isSavedQuery) =>
PasteFormat.CreateCustomAIFormat(CustomAIFormat, name, prompt, isSavedQuery, AvailableClipboardFormats, IsCustomAIServiceEnabled);
private void RefreshPasteFormats()
@ -208,7 +208,7 @@ namespace AdvancedPaste.ViewModels
UpdateFormats(
CustomActionPasteFormats,
IsCustomAIServiceEnabled ? _userSettings.CustomActions.Select(customAction => CreateAIServiceFormat(customAction.Name, customAction.Prompt, isSavedQuery: true)) : []);
IsCustomAIServiceEnabled ? _userSettings.CustomActions.Select(customAction => CreateCustomAIPasteFormat(customAction.Name, customAction.Prompt, isSavedQuery: true)) : []);
}
public void Dispose()
@ -436,7 +436,7 @@ namespace AdvancedPaste.ViewModels
if (customAction != null)
{
await ReadClipboardAsync();
await ExecutePasteFormatAsync(CreateAIServiceFormat(customAction.Name, customAction.Prompt, isSavedQuery: true), source);
await ExecutePasteFormatAsync(CreateCustomAIPasteFormat(customAction.Name, customAction.Prompt, isSavedQuery: true), source);
}
}
@ -445,7 +445,7 @@ namespace AdvancedPaste.ViewModels
var customAction = _userSettings.CustomActions
.FirstOrDefault(customAction => Models.KernelQueryCache.CacheKey.PromptComparer.Equals(customAction.Prompt, Query));
await ExecutePasteFormatAsync(CreateAIServiceFormat(customAction?.Name ?? "Default", Query, isSavedQuery: customAction != null), triggerSource);
await ExecutePasteFormatAsync(CreateCustomAIPasteFormat(customAction?.Name ?? "Default", Query, isSavedQuery: customAction != null), triggerSource);
}
private void HideWindow()

View File

@ -270,9 +270,9 @@ private:
}
}
void parse_hotkeys(PowerToysSettings::PowerToyValues& settings)
void read_settings(PowerToysSettings::PowerToyValues& settings)
{
auto settingsObject = settings.get_raw_json();
const auto settingsObject = settings.get_raw_json();
// Migrate Paste As Plain text shortcut
Hotkey old_paste_as_plain_hotkey;
@ -354,6 +354,21 @@ private:
}
}
}
if (settingsObject.GetView().Size())
{
const auto propertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES);
if (propertiesObject.HasKey(JSON_KEY_IS_ADVANCED_AI_ENABLED))
{
m_is_advanced_ai_enabled = propertiesObject.GetNamedObject(JSON_KEY_IS_ADVANCED_AI_ENABLED).GetNamedBoolean(JSON_KEY_VALUE);
}
if (propertiesObject.HasKey(JSON_KEY_SHOW_CUSTOM_PREVIEW))
{
m_preview_custom_format_output = propertiesObject.GetNamedObject(JSON_KEY_SHOW_CUSTOM_PREVIEW).GetNamedBoolean(JSON_KEY_VALUE);
}
}
}
bool is_process_running() const
@ -443,23 +458,7 @@ private:
PowerToysSettings::PowerToyValues settings =
PowerToysSettings::PowerToyValues::load_from_settings_file(get_key());
parse_hotkeys(settings);
const auto settingsObject = settings.get_raw_json();
if (settingsObject.GetView().Size())
{
const auto propertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES);
if (propertiesObject.HasKey(JSON_KEY_IS_ADVANCED_AI_ENABLED))
{
m_is_advanced_ai_enabled = propertiesObject.GetNamedObject(JSON_KEY_IS_ADVANCED_AI_ENABLED).GetNamedBoolean(JSON_KEY_VALUE);
}
if (propertiesObject.HasKey(JSON_KEY_SHOW_CUSTOM_PREVIEW))
{
m_preview_custom_format_output = propertiesObject.GetNamedObject(JSON_KEY_SHOW_CUSTOM_PREVIEW).GetNamedBoolean(JSON_KEY_VALUE);
}
}
read_settings(settings);
}
catch (std::exception&)
{
@ -821,23 +820,7 @@ public:
PowerToysSettings::PowerToyValues values =
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
parse_hotkeys(values);
const auto settingsObject = values.get_raw_json();
if (settingsObject.GetView().Size())
{
const auto propertiesObject = settingsObject.GetNamedObject(JSON_KEY_PROPERTIES);
if (propertiesObject.HasKey(JSON_KEY_IS_ADVANCED_AI_ENABLED))
{
m_is_advanced_ai_enabled = propertiesObject.GetNamedObject(JSON_KEY_IS_ADVANCED_AI_ENABLED).GetNamedBoolean(JSON_KEY_VALUE);
}
if (propertiesObject.HasKey(JSON_KEY_SHOW_CUSTOM_PREVIEW))
{
m_preview_custom_format_output = propertiesObject.GetNamedObject(JSON_KEY_SHOW_CUSTOM_PREVIEW).GetNamedBoolean(JSON_KEY_VALUE);
}
}
read_settings(values);
std::unordered_map<std::wstring, Hotkey> additionalActionMap;
for (const auto& action : m_additional_actions)