@trebco/treb 31.9.1 → 32.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/treb-spreadsheet.mjs +15 -15
- package/i18n/languages/treb-i18n-da.mjs +1 -0
- package/i18n/languages/treb-i18n-de.mjs +1 -0
- package/i18n/languages/treb-i18n-es.mjs +1 -0
- package/i18n/languages/treb-i18n-fr.mjs +1 -0
- package/i18n/languages/treb-i18n-it.mjs +1 -0
- package/i18n/languages/treb-i18n-nl.mjs +1 -0
- package/i18n/languages/treb-i18n-no.mjs +1 -0
- package/i18n/languages/treb-i18n-pl.mjs +1 -0
- package/i18n/languages/treb-i18n-pt.mjs +1 -0
- package/i18n/languages/treb-i18n-sv.mjs +1 -0
- package/package.json +1 -1
- package/treb-base-types/src/style.ts +20 -0
- package/treb-base-types/src/union.ts +6 -0
- package/treb-base-types/src/value-type.ts +13 -0
- package/treb-calculator/src/calculator.ts +20 -1
- package/treb-calculator/src/descriptors.ts +49 -4
- package/treb-calculator/src/expression-calculator.ts +263 -12
- package/treb-calculator/src/functions/base-functions.ts +49 -0
- package/treb-calculator/src/functions/fp.ts +339 -0
- package/treb-calculator/src/functions/gamma.ts +143 -0
- package/treb-calculator/src/functions/lambda-functions.ts +96 -0
- package/treb-calculator/src/functions/statistics-functions.ts +88 -0
- package/treb-data-model/src/data_model.ts +28 -13
- package/treb-data-model/src/named.ts +7 -0
- package/treb-data-model/src/sheet.ts +19 -2
- package/treb-embed/src/embedded-spreadsheet.ts +22 -5
- package/treb-embed/style/theme-defaults.scss +0 -22
- package/treb-grid/src/editors/editor.ts +14 -0
- package/treb-grid/src/types/grid.ts +74 -28
- package/treb-parser/src/parser-types.ts +24 -0
- package/treb-parser/src/parser.ts +157 -223
- package/dist/treb-export-worker.mjs +0 -2
- package/dist/treb.d.ts +0 -2235
- package/treb-calculator/tsconfig.json +0 -7
|
@@ -111,13 +111,17 @@ export class DataModel {
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
/**
|
|
114
|
-
*
|
|
114
|
+
* @param force_locale - always parse assuming a locale like en-us (comma
|
|
115
|
+
* argument separators). the current thinking is that this is required for
|
|
116
|
+
* XLSX import, although that might be incorrect.
|
|
115
117
|
*/
|
|
116
|
-
public UnserializeNames(names: SerializedNamed[], active_sheet?: Sheet) {
|
|
118
|
+
public UnserializeNames(names: SerializedNamed[], active_sheet?: Sheet, force_locale = false) {
|
|
117
119
|
|
|
118
120
|
this.parser.Save();
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
if (force_locale) {
|
|
122
|
+
this.parser.SetLocaleSettings(DecimalMarkType.Period, ArgumentSeparatorType.Comma);
|
|
123
|
+
}
|
|
124
|
+
|
|
121
125
|
//const sorted = names.map(named => {
|
|
122
126
|
for (const named of names) {
|
|
123
127
|
|
|
@@ -197,6 +201,7 @@ export class DataModel {
|
|
|
197
201
|
const named: SerializedNamed = {
|
|
198
202
|
name: entry.name,
|
|
199
203
|
expression: '',
|
|
204
|
+
type: entry.type,
|
|
200
205
|
};
|
|
201
206
|
|
|
202
207
|
if (entry.scope) {
|
|
@@ -239,6 +244,11 @@ export class DataModel {
|
|
|
239
244
|
return true;
|
|
240
245
|
});
|
|
241
246
|
|
|
247
|
+
// this is using the current locale settings, but unserialize
|
|
248
|
+
// assumes we are unserializing in US-style locale. I think we
|
|
249
|
+
// do that because excel always uses that? not sure, but we need
|
|
250
|
+
// to be consistent.
|
|
251
|
+
|
|
242
252
|
named.expression = this.parser.Render(entry.expression, { missing: '' });
|
|
243
253
|
|
|
244
254
|
}
|
|
@@ -601,9 +611,9 @@ export class DataModel {
|
|
|
601
611
|
* be inlined (assuming it's only called in one place), but we are breaking
|
|
602
612
|
* it out so we can develop/test/manage it.
|
|
603
613
|
*/
|
|
604
|
-
public TranslateFunction(value: string): string {
|
|
614
|
+
public TranslateFunction(value: string, options?: { r1c1?: boolean }): string {
|
|
605
615
|
if (this.language_map) {
|
|
606
|
-
return this.TranslateInternal(value, this.language_map, this.language_model?.boolean_true, this.language_model?.boolean_false);
|
|
616
|
+
return this.TranslateInternal(value, this.language_map, this.language_model?.boolean_true, this.language_model?.boolean_false, options);
|
|
607
617
|
}
|
|
608
618
|
return value;
|
|
609
619
|
}
|
|
@@ -612,14 +622,14 @@ export class DataModel {
|
|
|
612
622
|
* translate from local language -> common (english).
|
|
613
623
|
* @see TranslateFunction
|
|
614
624
|
*/
|
|
615
|
-
public UntranslateFunction(value: string): string {
|
|
625
|
+
public UntranslateFunction(value: string, options?: { r1c1?: boolean }): string {
|
|
616
626
|
if (this.reverse_language_map) {
|
|
617
|
-
return this.TranslateInternal(value, this.reverse_language_map, 'TRUE', 'FALSE');
|
|
627
|
+
return this.TranslateInternal(value, this.reverse_language_map, 'TRUE', 'FALSE', options);
|
|
618
628
|
}
|
|
619
629
|
return value;
|
|
620
630
|
}
|
|
621
631
|
|
|
622
|
-
public UntranslateData(value: CellValue|CellValue[]|CellValue[][]): CellValue|CellValue[]|CellValue[][] {
|
|
632
|
+
public UntranslateData(value: CellValue|CellValue[]|CellValue[][], options?: { r1c1?: boolean }): CellValue|CellValue[]|CellValue[][] {
|
|
623
633
|
|
|
624
634
|
if (Array.isArray(value)) {
|
|
625
635
|
|
|
@@ -628,7 +638,7 @@ export class DataModel {
|
|
|
628
638
|
if (Is2DArray(value)) {
|
|
629
639
|
return value.map(row => row.map(entry => {
|
|
630
640
|
if (entry && typeof entry === 'string' && entry[0] === '=') {
|
|
631
|
-
return this.UntranslateFunction(entry);
|
|
641
|
+
return this.UntranslateFunction(entry, options);
|
|
632
642
|
}
|
|
633
643
|
return entry;
|
|
634
644
|
}));
|
|
@@ -636,7 +646,7 @@ export class DataModel {
|
|
|
636
646
|
else {
|
|
637
647
|
return value.map(entry => {
|
|
638
648
|
if (entry && typeof entry === 'string' && entry[0] === '=') {
|
|
639
|
-
return this.UntranslateFunction(entry);
|
|
649
|
+
return this.UntranslateFunction(entry, options);
|
|
640
650
|
}
|
|
641
651
|
return entry;
|
|
642
652
|
});
|
|
@@ -646,7 +656,7 @@ export class DataModel {
|
|
|
646
656
|
else if (value && typeof value === 'string' && value[0] === '=') {
|
|
647
657
|
|
|
648
658
|
// single value
|
|
649
|
-
value = this.UntranslateFunction(value);
|
|
659
|
+
value = this.UntranslateFunction(value, options);
|
|
650
660
|
|
|
651
661
|
}
|
|
652
662
|
|
|
@@ -663,7 +673,10 @@ export class DataModel {
|
|
|
663
673
|
* FIXME: it's about time we started using proper maps, we dropped
|
|
664
674
|
* support for IE11 some time ago.
|
|
665
675
|
*/
|
|
666
|
-
private TranslateInternal(value: string, map: Record<string, string>, boolean_true?: string, boolean_false?: string): string {
|
|
676
|
+
private TranslateInternal(value: string, map: Record<string, string>, boolean_true?: string, boolean_false?: string, options?: { r1c1?: boolean }): string {
|
|
677
|
+
|
|
678
|
+
this.parser.Save();
|
|
679
|
+
this.parser.flags.r1c1 = options?.r1c1;
|
|
667
680
|
|
|
668
681
|
const parse_result = this.parser.Parse(value);
|
|
669
682
|
|
|
@@ -694,10 +707,12 @@ export class DataModel {
|
|
|
694
707
|
if (modified) {
|
|
695
708
|
return '=' + this.parser.Render(parse_result.expression, {
|
|
696
709
|
missing: '', boolean_true, boolean_false,
|
|
710
|
+
r1c1: options?.r1c1,
|
|
697
711
|
});
|
|
698
712
|
}
|
|
699
713
|
}
|
|
700
714
|
|
|
715
|
+
this.parser.Restore();
|
|
701
716
|
return value;
|
|
702
717
|
|
|
703
718
|
}
|
|
@@ -33,6 +33,7 @@ interface NamedRange {
|
|
|
33
33
|
area: Area;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/** @internal */
|
|
36
37
|
export type Named = (NamedExpression | NamedRange) & {
|
|
37
38
|
name: string; // canonical name
|
|
38
39
|
scope?: number; // scope to sheet by ID
|
|
@@ -57,6 +58,12 @@ export interface SerializedNamed {
|
|
|
57
58
|
/** scope is a sheet name (not ID) */
|
|
58
59
|
scope?: string;
|
|
59
60
|
|
|
61
|
+
/**
|
|
62
|
+
* adding type. this is optional, it's not used by tooling. it's
|
|
63
|
+
* just for informational purpopses for clients.
|
|
64
|
+
*/
|
|
65
|
+
type?: 'range'|'expression';
|
|
66
|
+
|
|
60
67
|
}
|
|
61
68
|
|
|
62
69
|
/**
|
|
@@ -1631,6 +1631,23 @@ export class Sheet {
|
|
|
1631
1631
|
cell.rendered_type = ValueType.dimensioned_quantity; // who cares about rendered_type? (...)
|
|
1632
1632
|
|
|
1633
1633
|
}
|
|
1634
|
+
else if (type === ValueType.function) {
|
|
1635
|
+
|
|
1636
|
+
/*
|
|
1637
|
+
// FIXME: lock down this type (function)
|
|
1638
|
+
|
|
1639
|
+
if ((cell.calculated as any)?.alt) {
|
|
1640
|
+
cell.formatted = (cell.calculated as any).alt.toString();
|
|
1641
|
+
cell.rendered_type = ValueType.string;
|
|
1642
|
+
}
|
|
1643
|
+
else
|
|
1644
|
+
*/
|
|
1645
|
+
|
|
1646
|
+
{
|
|
1647
|
+
cell.formatted = '𝑓()'; // FIXME
|
|
1648
|
+
cell.rendered_type = ValueType.string;
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1634
1651
|
else {
|
|
1635
1652
|
|
|
1636
1653
|
// why is this being treated as a number? (...)
|
|
@@ -2539,7 +2556,7 @@ export class Sheet {
|
|
|
2539
2556
|
cell_reference_map[c] = [];
|
|
2540
2557
|
for (let r = 0; r < column.length; r++) {
|
|
2541
2558
|
if (column[r]) {
|
|
2542
|
-
const style_as_json = JSON.stringify(column[r]);
|
|
2559
|
+
const style_as_json = Style.Serialize(column[r]); // JSON.stringify(column[r]);
|
|
2543
2560
|
if (style_as_json !== empty_json) {
|
|
2544
2561
|
let reference_index = cell_style_map[style_as_json];
|
|
2545
2562
|
if (typeof reference_index !== 'number') {
|
|
@@ -2562,7 +2579,7 @@ export class Sheet {
|
|
|
2562
2579
|
*/
|
|
2563
2580
|
const StyleToRef = (style: CellStyle) => {
|
|
2564
2581
|
|
|
2565
|
-
const style_as_json = JSON.stringify(style);
|
|
2582
|
+
const style_as_json = Style.Serialize(style); // JSON.stringify(style);
|
|
2566
2583
|
if (style_as_json === empty_json) {
|
|
2567
2584
|
return 0;
|
|
2568
2585
|
}
|
|
@@ -49,9 +49,9 @@ import type {
|
|
|
49
49
|
CondifionalFormatExpressionOptions,
|
|
50
50
|
ConditionalFormatCellMatchOptions,
|
|
51
51
|
ConditionalFormatCellMatch,
|
|
52
|
-
|
|
53
52
|
LanguageModel,
|
|
54
53
|
TranslatedFunctionDescriptor,
|
|
54
|
+
SerializedNamed,
|
|
55
55
|
|
|
56
56
|
} from 'treb-data-model';
|
|
57
57
|
|
|
@@ -2242,8 +2242,11 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
2242
2242
|
|
|
2243
2243
|
// console.info({events});
|
|
2244
2244
|
|
|
2245
|
+
// FIXME: composite? (...)
|
|
2246
|
+
|
|
2245
2247
|
for (const event of events) {
|
|
2246
2248
|
switch (event.type) {
|
|
2249
|
+
case 'composite':
|
|
2247
2250
|
case 'data':
|
|
2248
2251
|
recalc = true;
|
|
2249
2252
|
break;
|
|
@@ -4000,8 +4003,13 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
4000
4003
|
// API v1 OK
|
|
4001
4004
|
|
|
4002
4005
|
let area: Area | undefined;
|
|
4003
|
-
|
|
4004
|
-
|
|
4006
|
+
switch (event?.type) {
|
|
4007
|
+
case 'data':
|
|
4008
|
+
area = event.area;
|
|
4009
|
+
break;
|
|
4010
|
+
case 'composite':
|
|
4011
|
+
area = event.data_area;
|
|
4012
|
+
break;
|
|
4005
4013
|
}
|
|
4006
4014
|
|
|
4007
4015
|
this.calculator.Calculate(area);
|
|
@@ -4172,7 +4180,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
4172
4180
|
*
|
|
4173
4181
|
* @public
|
|
4174
4182
|
*/
|
|
4175
|
-
public Resolve(reference: string): ICellAddress | IArea | undefined {
|
|
4183
|
+
public Resolve(reference: string, options?: { r1c1?: boolean }): ICellAddress | IArea | undefined {
|
|
4176
4184
|
|
|
4177
4185
|
// API v1 OK
|
|
4178
4186
|
|
|
@@ -4183,7 +4191,7 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
4183
4191
|
// FIXME: we're using the sheet EnsureAddress method, but that should
|
|
4184
4192
|
// move either in here or into some sort of helper class
|
|
4185
4193
|
|
|
4186
|
-
const result = this.model.ResolveAddress(reference, this.grid.active_sheet);
|
|
4194
|
+
const result = this.model.ResolveAddress(reference, this.grid.active_sheet, options);
|
|
4187
4195
|
|
|
4188
4196
|
if (IsCellAddress(result)) {
|
|
4189
4197
|
return result.sheet_id ? result : undefined;
|
|
@@ -4418,6 +4426,10 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
4418
4426
|
|
|
4419
4427
|
}
|
|
4420
4428
|
|
|
4429
|
+
public ListNames(): SerializedNamed[] {
|
|
4430
|
+
return this.model.SerializeNames();
|
|
4431
|
+
}
|
|
4432
|
+
|
|
4421
4433
|
/**
|
|
4422
4434
|
* Create a named range or named expression. A named range refers to an
|
|
4423
4435
|
* address or range. A named expression can be any value or formula. To set
|
|
@@ -6445,7 +6457,10 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
6445
6457
|
model.named.Reset();
|
|
6446
6458
|
|
|
6447
6459
|
if (data.named) {
|
|
6460
|
+
|
|
6461
|
+
// use locale setting for parsing
|
|
6448
6462
|
this.model.UnserializeNames(data.named, this.grid.active_sheet);
|
|
6463
|
+
|
|
6449
6464
|
}
|
|
6450
6465
|
else {
|
|
6451
6466
|
|
|
@@ -6482,6 +6497,8 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
|
|
|
6482
6497
|
if (data.named_expressions) {
|
|
6483
6498
|
for (const pair of data.named_expressions) {
|
|
6484
6499
|
|
|
6500
|
+
// use locale setting for parsing
|
|
6501
|
+
|
|
6485
6502
|
this.model.UnserializeNames([{
|
|
6486
6503
|
name: pair.name,
|
|
6487
6504
|
expression: pair.expression,
|
|
@@ -33,24 +33,6 @@
|
|
|
33
33
|
$primary-selection-color: #4caaf1;
|
|
34
34
|
$primary-selection-color-unfocused: #acc0cf;
|
|
35
35
|
|
|
36
|
-
/*
|
|
37
|
-
$alternate-selection-color-1: rgb(251, 177, 60);
|
|
38
|
-
$alternate-selection-color-2: rgb(64, 192, 64);
|
|
39
|
-
$alternate-selection-color-3: rgb(182, 109, 13);
|
|
40
|
-
$alternate-selection-color-4: rgb(33, 118, 174);
|
|
41
|
-
$alternate-selection-color-5: rgb(254, 104, 71);
|
|
42
|
-
|
|
43
|
-
/ * *
|
|
44
|
-
* slightly darkening colors for text highlighting
|
|
45
|
-
* algo: convert to HSL; if L > .5, regenerate with L = .5; back to RGB (why?)
|
|
46
|
-
* /
|
|
47
|
-
$text-reference-color-1: rgb(250, 155, 5);
|
|
48
|
-
$text-reference-color-2: rgb(58, 173, 58);
|
|
49
|
-
$text-reference-color-3: rgb(182, 109, 13);
|
|
50
|
-
$text-reference-color-4: rgb(33, 118, 174);
|
|
51
|
-
$text-reference-color-5: rgb(254, 47, 1);
|
|
52
|
-
*/
|
|
53
|
-
|
|
54
36
|
.treb-main.treb-main {
|
|
55
37
|
|
|
56
38
|
--alternate-selection-color-1: rgb(251, 177, 60);
|
|
@@ -324,25 +306,21 @@ $text-reference-color-5: rgb(254, 47, 1);
|
|
|
324
306
|
|
|
325
307
|
/* span:nth-of-type(2n) { */
|
|
326
308
|
span.highlight-2 {
|
|
327
|
-
// color: $text-reference-color-2;
|
|
328
309
|
color: var(--text-reference-color-2);
|
|
329
310
|
}
|
|
330
311
|
|
|
331
312
|
/* span:nth-of-type(3n) { */
|
|
332
313
|
span.highlight-3 {
|
|
333
|
-
// color: $text-reference-color-3;
|
|
334
314
|
color: var(--text-reference-color-3);
|
|
335
315
|
}
|
|
336
316
|
|
|
337
317
|
/* span:nth-of-type(4n) { */
|
|
338
318
|
span.highlight-4 {
|
|
339
|
-
// color: $text-reference-color-4;
|
|
340
319
|
color: var(--text-reference-color-4);
|
|
341
320
|
}
|
|
342
321
|
|
|
343
322
|
/* span:nth-of-type(5n) { */
|
|
344
323
|
span.highlight-5 {
|
|
345
|
-
// color: $text-reference-color-5;
|
|
346
324
|
color: var(--text-reference-color-5);
|
|
347
325
|
}
|
|
348
326
|
|
|
@@ -1036,11 +1036,25 @@ export class Editor<E = FormulaEditorEvent> extends EventSource<E|FormulaEditorE
|
|
|
1036
1036
|
if (matcher) {
|
|
1037
1037
|
Promise.resolve().then(() => {
|
|
1038
1038
|
const exec_result = matcher.Exec({ text, cursor: substring_end.length });
|
|
1039
|
+
|
|
1040
|
+
// fix behavior around "f16round", which is a function we accidentally
|
|
1041
|
+
// inherit from Math in Safari and Firefox. it breaks arrow-selection
|
|
1042
|
+
// because it pops up an AC window. we don't want to break AC behavior
|
|
1043
|
+
// on tooltips, though, so we still want to call AC methods. just block
|
|
1044
|
+
// the completion list.
|
|
1045
|
+
|
|
1046
|
+
if (this.selecting && exec_result.completions?.length) {
|
|
1047
|
+
// console.info("Blocking completion list", JSON.stringify(exec_result.completions));
|
|
1048
|
+
exec_result.completions = undefined;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1039
1051
|
const node =
|
|
1040
1052
|
this.NodeAtIndex(exec_result.completions?.length ?
|
|
1041
1053
|
(exec_result.position || 0) :
|
|
1042
1054
|
(exec_result.function_position || 0));
|
|
1055
|
+
|
|
1043
1056
|
this.Autocomplete(exec_result, node);
|
|
1057
|
+
|
|
1044
1058
|
});
|
|
1045
1059
|
}
|
|
1046
1060
|
|
|
@@ -1284,7 +1284,7 @@ export class Grid extends GridBase {
|
|
|
1284
1284
|
this.model.named.Reset();
|
|
1285
1285
|
|
|
1286
1286
|
if (import_data.named) {
|
|
1287
|
-
this.model.UnserializeNames(import_data.named, this.active_sheet);
|
|
1287
|
+
this.model.UnserializeNames(import_data.named, this.active_sheet, true);
|
|
1288
1288
|
}
|
|
1289
1289
|
|
|
1290
1290
|
// FIXME: do we need to rebuild autocomplete here (A: yes)
|
|
@@ -2041,6 +2041,7 @@ export class Grid extends GridBase {
|
|
|
2041
2041
|
command.expression = parse_result.expression;
|
|
2042
2042
|
}
|
|
2043
2043
|
else {
|
|
2044
|
+
console.info({expression, parse_result});
|
|
2044
2045
|
throw new Error('invalid expression');
|
|
2045
2046
|
}
|
|
2046
2047
|
}
|
|
@@ -2350,11 +2351,12 @@ export class Grid extends GridBase {
|
|
|
2350
2351
|
|
|
2351
2352
|
|
|
2352
2353
|
// this is public so we need to (un)translate.
|
|
2353
|
-
|
|
2354
|
+
// console.info("PRE", {r1c1}, data);
|
|
2355
|
+
data = this.model.UntranslateData(data, { r1c1 });
|
|
2356
|
+
// console.info("POST", data, "\n");
|
|
2354
2357
|
|
|
2355
2358
|
// single value, easiest
|
|
2356
2359
|
if (!Array.isArray(data)) {
|
|
2357
|
-
|
|
2358
2360
|
if (recycle || array) {
|
|
2359
2361
|
this.ExecCommand({ key: CommandKey.SetRange, area: range, value: data, array, r1c1 });
|
|
2360
2362
|
}
|
|
@@ -4553,20 +4555,8 @@ export class Grid extends GridBase {
|
|
|
4553
4555
|
if (selecting_argument) {
|
|
4554
4556
|
this.UpdateSelectedArgument(selection);
|
|
4555
4557
|
}
|
|
4556
|
-
else
|
|
4557
|
-
|
|
4558
|
-
this.UpdateAddressLabel(undefined, selection.area.columns + 'C');
|
|
4559
|
-
}
|
|
4560
|
-
else if (selection.area.entire_row) {
|
|
4561
|
-
this.UpdateAddressLabel(undefined, selection.area.rows + 'R');
|
|
4562
|
-
}
|
|
4563
|
-
else if (selection.area.count > 1) {
|
|
4564
|
-
this.UpdateAddressLabel(undefined, selection.area.rows + 'R x ' +
|
|
4565
|
-
selection.area.columns + 'C');
|
|
4566
|
-
}
|
|
4567
|
-
else {
|
|
4568
|
-
this.UpdateAddressLabel(selection);
|
|
4569
|
-
}
|
|
4558
|
+
else {
|
|
4559
|
+
this.UpdateAddressLabelArea(selection); // 3R x 2C
|
|
4570
4560
|
}
|
|
4571
4561
|
}
|
|
4572
4562
|
}, () => {
|
|
@@ -5113,6 +5103,9 @@ export class Grid extends GridBase {
|
|
|
5113
5103
|
|
|
5114
5104
|
if (!selection.empty && (delta.columns || delta.rows)) {
|
|
5115
5105
|
if (this.BlockSelection(selection, !!event.shiftKey, delta.columns, delta.rows)) {
|
|
5106
|
+
if (event.shiftKey && !selecting_argument) {
|
|
5107
|
+
this.UpdateAddressLabelArea(selection);
|
|
5108
|
+
}
|
|
5116
5109
|
return;
|
|
5117
5110
|
}
|
|
5118
5111
|
}
|
|
@@ -5279,6 +5272,9 @@ export class Grid extends GridBase {
|
|
|
5279
5272
|
|
|
5280
5273
|
if (delta.rows || delta.columns) {
|
|
5281
5274
|
this.AdvanceSelection(delta, selection, within_selection, expand_selection, !editor_open);
|
|
5275
|
+
if (event.shiftKey && !selecting_argument) {
|
|
5276
|
+
this.UpdateAddressLabelArea(selection);
|
|
5277
|
+
}
|
|
5282
5278
|
}
|
|
5283
5279
|
|
|
5284
5280
|
}
|
|
@@ -5659,7 +5655,13 @@ export class Grid extends GridBase {
|
|
|
5659
5655
|
}
|
|
5660
5656
|
}
|
|
5661
5657
|
}
|
|
5662
|
-
if (formula_parse_result.
|
|
5658
|
+
if (formula_parse_result.expression) {
|
|
5659
|
+
|
|
5660
|
+
// we were previously looking at address arguments, and ignoring
|
|
5661
|
+
// ranges. this leads to inconsistent behavior. we'll now look at
|
|
5662
|
+
// ranges when inferring number format.
|
|
5663
|
+
|
|
5664
|
+
// there was also an issue with using the correct sheet, also fixed.
|
|
5663
5665
|
|
|
5664
5666
|
// this was set up to just use the first format we found.
|
|
5665
5667
|
// updating to change priority -- if the first one is a
|
|
@@ -5668,14 +5670,10 @@ export class Grid extends GridBase {
|
|
|
5668
5670
|
|
|
5669
5671
|
let found_number_format: string|undefined = undefined;
|
|
5670
5672
|
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
// FIXME: this should not be active_sheet
|
|
5677
|
-
|
|
5678
|
-
const test = this.active_sheet.CellData({ ...address });
|
|
5673
|
+
/** returns true if we've found a non-% number format */
|
|
5674
|
+
const Check = (address: ICellAddress, sheet = this.active_sheet) => {
|
|
5675
|
+
if (sheet.HasCellStyle({...address})) {
|
|
5676
|
+
const test = sheet.CellData({ ...address });
|
|
5679
5677
|
if (test.style && test.style.number_format) {
|
|
5680
5678
|
if (!found_number_format || /%/.test(found_number_format)) {
|
|
5681
5679
|
|
|
@@ -5685,13 +5683,43 @@ export class Grid extends GridBase {
|
|
|
5685
5683
|
|
|
5686
5684
|
found_number_format = NumberFormatCache.Translate(test.style.number_format);
|
|
5687
5685
|
if (!/%/.test(found_number_format)) {
|
|
5688
|
-
|
|
5686
|
+
return true;
|
|
5689
5687
|
}
|
|
5690
5688
|
|
|
5691
5689
|
}
|
|
5692
5690
|
}
|
|
5693
5691
|
}
|
|
5694
|
-
|
|
5692
|
+
return false;
|
|
5693
|
+
};
|
|
5694
|
+
|
|
5695
|
+
let finished = false;
|
|
5696
|
+
let sheet: Sheet|undefined = this.active_sheet;
|
|
5697
|
+
|
|
5698
|
+
this.parser.Walk(formula_parse_result.expression, unit => {
|
|
5699
|
+
|
|
5700
|
+
if (finished) {
|
|
5701
|
+
return false;
|
|
5702
|
+
}
|
|
5703
|
+
|
|
5704
|
+
switch (unit.type) {
|
|
5705
|
+
case 'address':
|
|
5706
|
+
this.model.ResolveSheetID(unit);
|
|
5707
|
+
sheet = this.model.sheets.Find(unit.sheet_id || 0);
|
|
5708
|
+
finished = finished || Check(unit, sheet);
|
|
5709
|
+
break;
|
|
5710
|
+
|
|
5711
|
+
case 'range':
|
|
5712
|
+
this.model.ResolveSheetID(unit);
|
|
5713
|
+
sheet = this.model.sheets.Find(unit.start.sheet_id || 0);
|
|
5714
|
+
for (const address of new Area(unit.start, unit.end)) {
|
|
5715
|
+
finished = finished || Check(address, sheet);
|
|
5716
|
+
if (finished) { break; }
|
|
5717
|
+
}
|
|
5718
|
+
break;
|
|
5719
|
+
}
|
|
5720
|
+
return !finished;
|
|
5721
|
+
|
|
5722
|
+
});
|
|
5695
5723
|
|
|
5696
5724
|
if (found_number_format) {
|
|
5697
5725
|
|
|
@@ -7024,6 +7052,24 @@ export class Grid extends GridBase {
|
|
|
7024
7052
|
}
|
|
7025
7053
|
}
|
|
7026
7054
|
|
|
7055
|
+
private UpdateAddressLabelArea(selection: GridSelection) {
|
|
7056
|
+
if (!selection.empty && !selection.area.entire_sheet) {
|
|
7057
|
+
if (selection.area.entire_column) {
|
|
7058
|
+
this.UpdateAddressLabel(undefined, selection.area.columns + 'C');
|
|
7059
|
+
}
|
|
7060
|
+
else if (selection.area.entire_row) {
|
|
7061
|
+
this.UpdateAddressLabel(undefined, selection.area.rows + 'R');
|
|
7062
|
+
}
|
|
7063
|
+
else if (selection.area.count > 1) {
|
|
7064
|
+
this.UpdateAddressLabel(undefined, selection.area.rows + 'R x ' +
|
|
7065
|
+
selection.area.columns + 'C');
|
|
7066
|
+
}
|
|
7067
|
+
else {
|
|
7068
|
+
this.UpdateAddressLabel(selection);
|
|
7069
|
+
}
|
|
7070
|
+
}
|
|
7071
|
+
}
|
|
7072
|
+
|
|
7027
7073
|
private UpdateAddressLabel(selection = this.primary_selection, text?: string) {
|
|
7028
7074
|
|
|
7029
7075
|
if (!this.formula_bar) { return; }
|
|
@@ -167,6 +167,17 @@ export interface UnitCall extends BaseUnit {
|
|
|
167
167
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
/**
|
|
171
|
+
* new call type: implicit. we might merge these.
|
|
172
|
+
*/
|
|
173
|
+
export interface UnitImplicitCall extends BaseUnit {
|
|
174
|
+
type: 'implicit-call';
|
|
175
|
+
position: number;
|
|
176
|
+
args: ExpressionUnit[];
|
|
177
|
+
call: ExpressionUnit;
|
|
178
|
+
|
|
179
|
+
}
|
|
180
|
+
|
|
170
181
|
/**
|
|
171
182
|
* this isn't an output type (unless parsing fails), but it's useful
|
|
172
183
|
* to be able to pass these around with the same semantics.
|
|
@@ -177,6 +188,14 @@ export interface UnitOperator extends BaseUnit {
|
|
|
177
188
|
operator: string;
|
|
178
189
|
}
|
|
179
190
|
|
|
191
|
+
/**
|
|
192
|
+
* also not an output type
|
|
193
|
+
*/
|
|
194
|
+
export interface UnitGroupSeparator extends BaseUnit {
|
|
195
|
+
type: 'group-separator';
|
|
196
|
+
position: number;
|
|
197
|
+
}
|
|
198
|
+
|
|
180
199
|
/**
|
|
181
200
|
* expression unit representing a binary operation. operations may be
|
|
182
201
|
* re-ordered based on precendence.
|
|
@@ -259,9 +278,11 @@ export type BaseExpressionUnit =
|
|
|
259
278
|
| UnitArray
|
|
260
279
|
| UnitIdentifier
|
|
261
280
|
| UnitCall
|
|
281
|
+
| UnitImplicitCall
|
|
262
282
|
| UnitMissing
|
|
263
283
|
| UnitGroup
|
|
264
284
|
| UnitOperator
|
|
285
|
+
| UnitGroupSeparator
|
|
265
286
|
| UnitBinary
|
|
266
287
|
| UnitUnary
|
|
267
288
|
| UnitAddress
|
|
@@ -424,6 +445,9 @@ export interface RenderOptions {
|
|
|
424
445
|
/** base for offsetting relative R1C1 addresses */
|
|
425
446
|
r1c1_base?: UnitAddress;
|
|
426
447
|
|
|
448
|
+
/** force addresses to be relative */
|
|
449
|
+
r1c1_force_relative?: boolean;
|
|
450
|
+
|
|
427
451
|
/** if we're just translating, don't have to render addresses */
|
|
428
452
|
pass_through_addresses?: boolean;
|
|
429
453
|
|