Skip to content

Commit cd13fc3

Browse files
committed
Merge remote-tracking branch 'origin/main' into save_snippet
2 parents d6873c1 + c52ba7d commit cd13fc3

File tree

100 files changed

+2188
-1126
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+2188
-1126
lines changed

.github/actions/spelling/allow/allow.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ hyperlink
5656
hyperlinking
5757
hyperlinks
5858
iconify
59+
ID
5960
img
6061
inlined
6162
issuetitle

.github/actions/spelling/expect/expect.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,7 @@ FILTERONPASTE
609609
FINDCASE
610610
FINDDLG
611611
FINDDOWN
612+
FINDREGEX
612613
FINDSTRINGEXACT
613614
FINDUP
614615
FIter
@@ -821,6 +822,7 @@ idllib
821822
IDOK
822823
IDR
823824
idth
825+
IDTo
824826
IDXGI
825827
IEnd
826828
IEnum
@@ -1869,7 +1871,7 @@ unk
18691871
unknwn
18701872
UNORM
18711873
unparseable
1872-
unregistering
1874+
Unregistering
18731875
untextured
18741876
UPDATEDISPLAY
18751877
UPDOWN

build/pipelines/ci-caching.yml

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
trigger:
2+
batch: true
3+
# branches:
4+
# include:
5+
# - main
6+
# - feature/*
7+
# - gh-readonly-queue/*
8+
# paths:
9+
# exclude:
10+
# - doc/*
11+
# - samples/*
12+
# - tools/*
13+
14+
#pr:
15+
# branches:
16+
# include:
17+
# - main
18+
# - feature/*
19+
# paths:
20+
# exclude:
21+
# - doc/*
22+
# - samples/*
23+
# - tools/*
24+
25+
variables:
26+
- name: runCodesignValidationInjectionBG
27+
value: false
28+
29+
# 0.0.yyMM.dd##
30+
# 0.0.1904.0900
31+
name: 0.0.$(Date:yyMM).$(Date:dd)$(Rev:rr)
32+
33+
parameters:
34+
- name: auditMode
35+
displayName: "Build in Audit Mode (x64)"
36+
type: boolean
37+
default: true
38+
- name: runTests
39+
displayName: "Run Tests"
40+
type: boolean
41+
default: true
42+
- name: buildPlatforms
43+
type: object
44+
default:
45+
- x64
46+
- x86
47+
- arm64
48+
49+
stages:
50+
- ${{ if eq(parameters.auditMode, true) }}:
51+
- stage: Audit_x64
52+
displayName: Audit Mode
53+
dependsOn: []
54+
jobs:
55+
- template: ./templates-v2/job-build-project.yml
56+
parameters:
57+
pool:
58+
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
59+
name: SHINE-OSS-L
60+
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
61+
name: SHINE-INT-L
62+
buildPlatforms: [x64]
63+
buildConfigurations: [AuditMode]
64+
buildEverything: true
65+
keepAllExpensiveBuildOutputs: false
66+
67+
- ${{ each platform in parameters.buildPlatforms }}:
68+
- stage: Build_${{ platform }}
69+
displayName: Build ${{ platform }}
70+
dependsOn: []
71+
jobs:
72+
- template: ./templates-v2/job-build-project.yml
73+
parameters:
74+
pool:
75+
${{ if eq(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
76+
name: SHINE-OSS-L
77+
${{ if ne(variables['System.CollectionUri'], 'https://dev.azure.com/ms/') }}:
78+
name: SHINE-INT-L
79+
buildPlatforms:
80+
- ${{ platform }}
81+
buildConfigurations: [Release]
82+
buildEverything: true
83+
keepAllExpensiveBuildOutputs: false
84+
85+
- ${{ if eq(parameters.runTests, true) }}:
86+
- stage: Test_${{ platform }}
87+
displayName: Test ${{ platform }}
88+
dependsOn:
89+
- Build_${{ platform }}
90+
condition: succeeded()
91+
jobs:
92+
- template: ./templates-v2/job-test-project.yml
93+
parameters:
94+
platform: ${{ platform }}
95+
# The tests might be run more than once; log one artifact per attempt.
96+
outputArtifactStem: -$(System.JobAttempt)

doc/cascadia/profiles.schema.json

Lines changed: 70 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,8 @@
629629
"folder",
630630
"separator",
631631
"remainingProfiles",
632-
"matchProfiles"
632+
"matchProfiles",
633+
"action"
633634
]
634635
},
635636
"NewTabMenuEntry": {
@@ -781,6 +782,28 @@
781782
}
782783
]
783784
},
785+
"ActionEntry": {
786+
"description": "An action in the new tab dropdown",
787+
"allOf": [
788+
{
789+
"$ref": "#/$defs/NewTabMenuEntry"
790+
},
791+
{
792+
"type": "object",
793+
"properties": {
794+
"type": {
795+
"type": "string",
796+
"const": "action"
797+
},
798+
"id": {
799+
"type": "string",
800+
"default": "",
801+
"description": "The ID of the action to show in this entry"
802+
}
803+
}
804+
}
805+
]
806+
},
784807
"SwitchToAdjacentTabArgs": {
785808
"oneOf": [
786809
{
@@ -2054,11 +2077,14 @@
20542077
},
20552078
{
20562079
"$ref": "#/$defs/RemainingProfilesEntry"
2080+
},
2081+
{
2082+
"$ref": "#/$defs/ActionEntry"
20572083
}
20582084
]
20592085
}
20602086
},
2061-
"Keybinding": {
2087+
"FullCommand": {
20622088
"additionalProperties": false,
20632089
"properties": {
20642090
"command": {
@@ -2186,21 +2212,6 @@
21862212
}
21872213
]
21882214
},
2189-
"keys": {
2190-
"description": "Defines the key combinations used to call the command. It must be composed of...\n -any number of modifiers (ctrl/alt/shift)\n -a non-modifier key",
2191-
"oneOf": [
2192-
{
2193-
"$ref": "#/$defs/KeyChordSegment"
2194-
},
2195-
{
2196-
"items": {
2197-
"$ref": "#/$defs/KeyChordSegment"
2198-
},
2199-
"minItems": 1,
2200-
"type": "array"
2201-
}
2202-
]
2203-
},
22042215
"icon": {
22052216
"$ref": "#/$defs/Icon"
22062217
},
@@ -2235,10 +2246,10 @@
22352246
"type": "object",
22362247
"properties": {
22372248
"command": {
2238-
"$ref": "#/$defs/Keybinding/properties/command"
2249+
"$ref": "#/$defs/FullCommand/properties/command"
22392250
},
22402251
"name": {
2241-
"$ref": "#/$defs/Keybinding/properties/name"
2252+
"$ref": "#/$defs/FullCommand/properties/name"
22422253
}
22432254
}
22442255
},
@@ -2261,6 +2272,44 @@
22612272
],
22622273
"type": "object"
22632274
},
2275+
"Keybinding": {
2276+
"additionalProperties": false,
2277+
"properties": {
2278+
"id": {
2279+
"description": "The ID of the command this keybinding should execute.",
2280+
"type": "string"
2281+
},
2282+
"keys": {
2283+
"description": "Defines the key combinations used to call the command. It must be composed of...\n -any number of modifiers (ctrl/alt/shift)\n -a non-modifier key",
2284+
"oneOf": [
2285+
{
2286+
"$ref": "#/$defs/KeyChordSegment"
2287+
},
2288+
{
2289+
"items": {
2290+
"$ref": "#/$defs/KeyChordSegment"
2291+
},
2292+
"minItems": 1,
2293+
"type": "array"
2294+
}
2295+
]
2296+
}
2297+
},
2298+
"anyOf": [
2299+
{
2300+
"required": [
2301+
"keys",
2302+
"id"
2303+
]
2304+
},
2305+
{
2306+
"required": [
2307+
"keys"
2308+
]
2309+
}
2310+
],
2311+
"type": "object"
2312+
},
22642313
"Globals": {
22652314
"additionalProperties": true,
22662315
"description": "Properties that affect the entire window, regardless of the profile settings.",
@@ -2464,12 +2513,12 @@
24642513
"actions": {
24652514
"description": "Properties are specific to each custom action.",
24662515
"items": {
2467-
"$ref": "#/$defs/Keybinding"
2516+
"$ref": "#/$defs/FullCommand"
24682517
},
24692518
"type": "array"
24702519
},
24712520
"keybindings": {
2472-
"description": "[deprecated] Use actions instead.",
2521+
"description": "A list of keychords bound to action IDs",
24732522
"deprecated": true,
24742523
"items": {
24752524
"$ref": "#/$defs/Keybinding"

src/buffer/out/UTextAdapter.cpp

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -186,23 +186,22 @@ catch (...)
186186
static UBool U_CALLCONV utextAccess(UText* ut, int64_t nativeIndex, UBool forward) noexcept
187187
try
188188
{
189-
if (nativeIndex < 0)
190-
{
191-
nativeIndex = 0;
192-
}
193-
194189
auto neededIndex = nativeIndex;
190+
// This will make it simpler for us to search the row that contains the nativeIndex,
191+
// because we'll now only need to check for `start<=index<limit` and nothing else.
195192
if (!forward)
196193
{
197194
neededIndex--;
198195
}
199196

200197
const auto& textBuffer = *static_cast<const TextBuffer*>(ut->context);
201198
const auto range = accessRowRange(ut);
202-
auto start = ut->chunkNativeStart;
203-
auto limit = ut->chunkNativeLimit;
199+
const auto startOld = ut->chunkNativeStart;
200+
const auto limitOld = ut->chunkNativeLimit;
201+
auto start = startOld;
202+
auto limit = limitOld;
204203

205-
if (neededIndex < start || neededIndex >= limit)
204+
if (neededIndex < startOld || neededIndex >= limitOld)
206205
{
207206
auto y = accessCurrentRow(ut);
208207
std::wstring_view text;
@@ -215,8 +214,7 @@ try
215214
--y;
216215
if (y < range.begin)
217216
{
218-
assert(false);
219-
return false;
217+
break;
220218
}
221219

222220
const auto& row = textBuffer.GetRowByOffset(y);
@@ -235,8 +233,7 @@ try
235233
++y;
236234
if (y >= range.end)
237235
{
238-
assert(false);
239-
return false;
236+
break;
240237
}
241238

242239
const auto& row = textBuffer.GetRowByOffset(y);
@@ -249,38 +246,50 @@ try
249246
} while (neededIndex >= limit);
250247
}
251248

252-
if (!wasWrapForced)
249+
assert(start >= 0);
250+
// If we have already calculated the total length we can also assert that the limit is in range.
251+
assert(ut->p == nullptr || static_cast<size_t>(limit) <= accessLength(ut));
252+
253+
// Even if we went out-of-bounds, we still need to update the chunkContents to contain the first/last chunk.
254+
if (limit != limitOld)
253255
{
254-
const auto newSize = text.size() + 1;
255-
const auto buffer = RefcountBuffer::EnsureCapacityForOverwrite(accessBuffer(ut), newSize);
256+
if (!wasWrapForced)
257+
{
258+
const auto newSize = text.size() + 1;
259+
const auto buffer = RefcountBuffer::EnsureCapacityForOverwrite(accessBuffer(ut), newSize);
256260

257-
memcpy(&buffer->data[0], text.data(), text.size() * sizeof(wchar_t));
258-
til::at(buffer->data, text.size()) = L'\n';
261+
memcpy(&buffer->data[0], text.data(), text.size() * sizeof(wchar_t));
262+
til::at(buffer->data, text.size()) = L'\n';
259263

260-
text = { &buffer->data[0], newSize };
261-
accessBuffer(ut) = buffer;
262-
}
264+
text = { &buffer->data[0], newSize };
265+
accessBuffer(ut) = buffer;
266+
}
263267

264-
accessCurrentRow(ut) = y;
265-
ut->chunkNativeStart = start;
266-
ut->chunkNativeLimit = limit;
267-
ut->chunkLength = gsl::narrow_cast<int32_t>(text.size());
268+
accessCurrentRow(ut) = y;
269+
ut->chunkNativeStart = start;
270+
ut->chunkNativeLimit = limit;
271+
ut->chunkLength = gsl::narrow_cast<int32_t>(text.size());
268272
#pragma warning(suppress : 26490) // Don't use reinterpret_cast (type.1).
269-
ut->chunkContents = reinterpret_cast<const char16_t*>(text.data());
270-
ut->nativeIndexingLimit = ut->chunkLength;
273+
ut->chunkContents = reinterpret_cast<const char16_t*>(text.data());
274+
ut->nativeIndexingLimit = ut->chunkLength;
275+
}
271276
}
272277

273-
auto offset = gsl::narrow_cast<int32_t>(nativeIndex - start);
274-
278+
// The ICU documentation is a little bit misleading. It states:
279+
// > @param forward [...] If true, start<=index<limit. If false, [...] start<index<=limit.
280+
// but that's just for finding the target chunk. The chunkOffset is not actually constrained to that!
281+
// std::clamp will perform a<=b<=c, which is what we want.
282+
const auto clampedIndex = std::clamp(nativeIndex, start, limit);
283+
auto offset = gsl::narrow_cast<int32_t>(clampedIndex - start);
275284
// Don't leave the offset on a trailing surrogate pair. See U16_SET_CP_START.
276285
// This assumes that the TextBuffer contains valid UTF-16 which may theoretically not be the case.
277286
if (offset > 0 && offset < ut->chunkLength && U16_IS_TRAIL(til::at(ut->chunkContents, offset)))
278287
{
279288
offset--;
280289
}
281-
282290
ut->chunkOffset = offset;
283-
return true;
291+
292+
return neededIndex >= start && neededIndex < limit;
284293
}
285294
catch (...)
286295
{

0 commit comments

Comments
 (0)