Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions src/officecli/Core/HtmlScreenshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ private static (bool, string?) TryChrome(string url, string outPath, int w, int

private static string? FindChrome()
{
string[] names = ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser",
string[] names = ["chrome-headless-shell", "google-chrome", "google-chrome-stable", "chromium", "chromium-browser",
"chrome", "microsoft-edge", "microsoft-edge-stable", "msedge"];
var pathHit = WhichFirst(names);
if (pathHit != null) return pathHit;
Expand All @@ -437,12 +437,32 @@ private static (bool, string?) TryChrome(string url, string outPath, int w, int
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
string localAppData = Environment.GetEnvironmentVariable("LOCALAPPDATA") ?? "";
string userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);

// Search ms-playwright / puppeteer installation directories for chrome-headless-shell.exe
foreach (var baseDir in new[] { localAppData, userProfile })
{
if (string.IsNullOrEmpty(baseDir)) continue;
var pwDir = Path.Combine(baseDir, "ms-playwright");
if (Directory.Exists(pwDir))
{
try
{
foreach (var exe in Directory.GetFiles(pwDir, "chrome-headless-shell.exe", SearchOption.AllDirectories))
abs.Add(exe);
}
catch { }
}
}

string[] roots = [
Environment.GetEnvironmentVariable("PROGRAMFILES") ?? @"C:\Program Files",
Environment.GetEnvironmentVariable("PROGRAMFILES(X86)") ?? @"C:\Program Files (x86)",
Environment.GetEnvironmentVariable("LOCALAPPDATA") ?? "",
localAppData,
];
string[] suffixes = [
@"Google\Chrome\Application\chrome-headless-shell.exe",
@"Google\Chrome\Application\chrome.exe",
@"Chromium\Application\chrome.exe",
@"Microsoft\Edge\Application\msedge.exe",
Expand Down
3 changes: 3 additions & 0 deletions src/officecli/Handlers/Excel/ExcelHandler.Add.Cells.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1245,6 +1245,7 @@ private string AddRun(string parentPath, string type, InsertPosition? position,
new Text(runExistingText) { Space = SpaceProcessingModeValues.Preserve }));
runCell.RemoveAllChildren<InlineString>();
runSst.AppendChild(runSsi);
InvalidateSharedStringCache();
var newSstIdx = runSst.Elements<SharedStringItem>().Count() - 1;
runCell.CellValue = new CellValue(newSstIdx.ToString());
runCell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
Expand Down Expand Up @@ -1563,6 +1564,7 @@ private void ApplyRichTextToCell(Cell cell, Dictionary<string, string> propertie
}

sst.AppendChild(ssi);
InvalidateSharedStringCache();
sst.Count = (uint)sst.Elements<SharedStringItem>().Count();
sst.UniqueCount = sst.Count;

Expand Down Expand Up @@ -1621,6 +1623,7 @@ private void ApplyPhoneticToCell(Cell cell, WorksheetPart wsPart,
ssi.AppendChild(rPh);

sst.AppendChild(ssi);
InvalidateSharedStringCache();
sst.Count = (uint)sst.Elements<SharedStringItem>().Count();
sst.UniqueCount = sst.Count;

Expand Down
51 changes: 47 additions & 4 deletions src/officecli/Handlers/Excel/ExcelHandler.Helpers.Cell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,48 @@ public partial class ExcelHandler
$"Unknown totals-row function '{tok}'. Valid: sum, average, count, countNums, max, min, stdDev, var, none, custom.")
};

private List<SharedStringItem>? _sharedStringItemCache;
private List<string>? _sharedStringCache;

private List<SharedStringItem> GetSharedStringItemCache()
{
if (_sharedStringItemCache != null) return _sharedStringItemCache;
var sst = _doc.WorkbookPart?.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
if (sst?.SharedStringTable == null) return _sharedStringItemCache = new List<SharedStringItem>();

var list = new List<SharedStringItem>();
foreach (var item in sst.SharedStringTable.Elements<SharedStringItem>())
{
list.Add(item);
}
return _sharedStringItemCache = list;
}

private List<string> GetSharedStringCache()
{
if (_sharedStringCache != null) return _sharedStringCache;
var items = GetSharedStringItemCache();
var list = new List<string>(items.Count);
foreach (var item in items)
{
list.Add(item.InnerText ?? "");
}
return _sharedStringCache = list;
}

/// <summary>
/// Must be called whenever a new SharedStringItem is appended to or removed
/// from the SharedStringTable so that the next GetCellDisplayValue call
/// rebuilds the cache from the updated table.
/// </summary>
private void InvalidateSharedStringCache()
{
_sharedStringCache = null;
_sharedStringItemCache = null;
}



private string GetCellDisplayValue(Cell cell, Core.FormulaEvaluator? evaluator = null)
{
if (cell.DataType?.Value == CellValues.InlineString)
Expand All @@ -49,12 +91,13 @@ private string GetCellDisplayValue(Cell cell, Core.FormulaEvaluator? evaluator =

if (cell.DataType?.Value == CellValues.SharedString)
{
var sst = _doc.WorkbookPart?.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
if (sst?.SharedStringTable != null && int.TryParse(value, out int idx))
if (int.TryParse(value, out int idx))
{
var item = sst.SharedStringTable.Elements<SharedStringItem>().ElementAtOrDefault(idx);
return item?.InnerText ?? value;
var cache = GetSharedStringCache();
if (idx >= 0 && idx < cache.Count)
return cache[idx];
}
return value;
}

// Boolean cells store 0/1 in <v> per the OOXML spec, but Excel displays
Expand Down
7 changes: 4 additions & 3 deletions src/officecli/Handlers/Excel/ExcelHandler.HtmlPreview.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2935,9 +2935,10 @@ private static (double mantissa, int exp) NormalizeScientific(double value)
var value = cell.CellValue?.Text;
if (value == null || !int.TryParse(value, out int idx)) return null;

var sst = _doc.WorkbookPart?.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
var item = sst?.SharedStringTable?.Elements<SharedStringItem>().ElementAtOrDefault(idx);
if (item == null) return null;
var items = GetSharedStringItemCache();
if (idx < 0 || idx >= items.Count) return null;
var item = items[idx];


var runs = item.Elements<Run>().ToList();
// Only worth wrapping when at least one run carries explicit run-properties;
Expand Down