[cmdpal] Port v1 calculator extension (#38629)

* init

* update

* Remove duplicated cp command

* Change the long desc

* Update notice.md

* Use the same icon for fallback item

* Add Rappl to expect list

* update notice.md

* Move the original order back.

* Make Radians become default choice

* Fix empty result

* Remove unused settings.
Move history back.
Refactory the query logic

* fix typo

* merge main

* CmdPal: minor calc updates (#38914)

A bunch of calc updates

* maintain the visibility of the history
* add other formats to the context menu #38708
* some other icon tidying

---------

Co-authored-by: Yu Leng (from Dev Box) <yuleng@microsoft.com>
Co-authored-by: Mike Griese <migrie@microsoft.com>
This commit is contained in:
Yu Leng
2025-04-17 14:59:10 +08:00
committed by GitHub
parent 4f9e829155
commit 6cf73ce839
19 changed files with 1565 additions and 154 deletions

View File

@@ -0,0 +1,127 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Threading;
using Microsoft.CmdPal.Ext.Calc.Helper;
using Microsoft.CmdPal.Ext.Calc.Properties;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.Calc.Pages;
// The calculator page is a dynamic list page
// * The first command is where we display the results. Title=result, Subtitle=query
// - The default command is `SaveCommand`.
// - When you save, insert into list at spot 1
// - change SearchText to the result
// - MoreCommands: a single `CopyCommand` to copy the result to the clipboard
// * The rest of the items are previously saved results
// - Command is a CopyCommand
// - Each item also sets the TextToSuggest to the result
public sealed partial class CalculatorListPage : DynamicListPage
{
private readonly Lock _resultsLock = new();
private readonly SettingsManager _settingsManager;
private readonly List<ListItem> _items = [];
private readonly List<ListItem> history = [];
private readonly ListItem _emptyItem;
// This is the text that saved when the user click the result.
// We need to avoid the double calculation. This may cause some wierd behaviors.
private string skipQuerySearchText = string.Empty;
public CalculatorListPage(SettingsManager settings)
{
_settingsManager = settings;
Icon = CalculatorIcons.ProviderIcon;
Name = Resources.calculator_title;
PlaceholderText = Resources.calculator_placeholder_text;
Id = "com.microsoft.cmdpal.calculator";
_emptyItem = new ListItem(new NoOpCommand())
{
Title = Resources.calculator_placeholder_text,
Icon = CalculatorIcons.ResultIcon,
};
EmptyContent = new CommandItem(new NoOpCommand())
{
Icon = CalculatorIcons.ProviderIcon,
Title = Resources.calculator_placeholder_text,
};
UpdateSearchText(string.Empty, string.Empty);
}
public override void UpdateSearchText(string oldSearch, string newSearch)
{
if (oldSearch == newSearch)
{
return;
}
if (!string.IsNullOrEmpty(skipQuerySearchText) && newSearch == skipQuerySearchText)
{
// only skip once.
skipQuerySearchText = string.Empty;
return;
}
skipQuerySearchText = string.Empty;
_emptyItem.Subtitle = newSearch;
var result = QueryHelper.Query(newSearch, _settingsManager, false, HandleSave);
UpdateResult(result);
}
private void UpdateResult(ListItem result)
{
lock (_resultsLock)
{
this._items.Clear();
if (result != null)
{
this._items.Add(result);
}
else
{
_items.Add(_emptyItem);
}
this._items.AddRange(history);
}
RaiseItemsChanged(this._items.Count);
}
private void HandleSave(object sender, object args)
{
var lastResult = _items[0].Title;
if (!string.IsNullOrEmpty(lastResult))
{
var li = new ListItem(new CopyTextCommand(lastResult))
{
Title = _items[0].Title,
Subtitle = _items[0].Subtitle,
TextToSuggest = lastResult,
};
history.Insert(0, li);
_items.Insert(1, li);
// Why we need to clean the query record? Removed, but if necessary, please move it back.
// _items[0].Subtitle = string.Empty;
// this change will call the UpdateSearchText again.
// We need to avoid it.
skipQuerySearchText = lastResult;
SearchText = lastResult;
this.RaiseItemsChanged(this._items.Count);
}
}
public override IListItem[] GetItems() => _items.ToArray();
}

View File

@@ -0,0 +1,52 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CmdPal.Ext.Calc.Helper;
using Microsoft.CmdPal.Ext.Calc.Properties;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.Calc.Pages;
public sealed partial class FallbackCalculatorItem : FallbackCommandItem
{
private readonly CopyTextCommand _copyCommand = new(string.Empty);
private readonly SettingsManager _settings;
public FallbackCalculatorItem(SettingsManager settings)
: base(new NoOpCommand(), Resources.calculator_title)
{
Command = _copyCommand;
_copyCommand.Name = string.Empty;
Title = string.Empty;
Subtitle = Resources.calculator_placeholder_text;
Icon = CalculatorIcons.ProviderIcon;
_settings = settings;
}
public override void UpdateQuery(string query)
{
var result = QueryHelper.Query(query, _settings, true, null);
if (result == null)
{
_copyCommand.Text = string.Empty;
_copyCommand.Name = string.Empty;
Title = string.Empty;
Subtitle = string.Empty;
MoreCommands = [];
return;
}
_copyCommand.Text = result.Title;
_copyCommand.Name = string.IsNullOrWhiteSpace(query) ? string.Empty : Resources.calculator_copy_command_name;
Title = result.Title;
// we have to make the subtitle the equation,
// so that we will still string match the original query
// Otherwise, something like 1+2 will have a title of "3" and not match
Subtitle = query;
MoreCommands = result.MoreCommands;
}
}