Skip to content

Commit 9dc7dd9

Browse files
committed
Merge branch 'main' into aiday/toggleDiffAsSetting
2 parents 35d1b2d + 43650e2 commit 9dc7dd9

File tree

73 files changed

+1952
-902
lines changed

Some content is hidden

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

73 files changed

+1952
-902
lines changed

cli/src/commands/args.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,10 @@ pub struct TunnelServiceInstallArgs {
649649
/// If set, the user accepts the server license terms and the server will be started without a user prompt.
650650
#[clap(long)]
651651
pub accept_server_license_terms: bool,
652+
653+
/// Sets the machine name for port forwarding service
654+
#[clap(long)]
655+
pub name: Option<String>,
652656
}
653657

654658
#[derive(Args, Debug, Clone)]

cli/src/commands/tunnels.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,17 @@ pub async fn service(
135135
let manager = create_service_manager(ctx.log.clone(), &ctx.paths);
136136
match service_args {
137137
TunnelServiceSubCommands::Install(args) => {
138-
// ensure logged in, otherwise subsequent serving will fail
139-
Auth::new(&ctx.paths, ctx.log.clone())
140-
.get_credential()
141-
.await?;
138+
let auth = Auth::new(&ctx.paths, ctx.log.clone());
139+
140+
if let Some(name) = &args.name {
141+
// ensure the name matches, and tunnel exists
142+
dev_tunnels::DevTunnels::new(&ctx.log, auth, &ctx.paths)
143+
.rename_tunnel(name)
144+
.await?;
145+
} else {
146+
// still ensure they're logged in, otherwise subsequent serving will fail
147+
auth.get_credential().await?;
148+
}
142149

143150
// likewise for license consent
144151
legal::require_consent(&ctx.paths, args.accept_server_license_terms)?;
@@ -203,20 +210,20 @@ pub async fn user(ctx: CommandContext, user_args: TunnelUserSubCommands) -> Resu
203210
Ok(0)
204211
}
205212

206-
/// Remove the tunnel used by this gateway, if any.
213+
/// Remove the tunnel used by this tunnel, if any.
207214
pub async fn rename(ctx: CommandContext, rename_args: TunnelRenameArgs) -> Result<i32, AnyError> {
208215
let auth = Auth::new(&ctx.paths, ctx.log.clone());
209216
let mut dt = dev_tunnels::DevTunnels::new(&ctx.log, auth, &ctx.paths);
210217
dt.rename_tunnel(&rename_args.name).await?;
211218
ctx.log.result(format!(
212-
"Successfully renamed this gateway to {}",
219+
"Successfully renamed this tunnel to {}",
213220
&rename_args.name
214221
));
215222

216223
Ok(0)
217224
}
218225

219-
/// Remove the tunnel used by this gateway, if any.
226+
/// Remove the tunnel used by this tunnel, if any.
220227
pub async fn unregister(ctx: CommandContext) -> Result<i32, AnyError> {
221228
let auth = Auth::new(&ctx.paths, ctx.log.clone());
222229
let mut dt = dev_tunnels::DevTunnels::new(&ctx.log, auth, &ctx.paths);

cli/src/rpc.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ impl<S: Serialization, C: Send + Sync + 'static> RpcMethodBuilder<S, C> {
117117
Ok(p) => p,
118118
Err(err) => {
119119
return id.map(|id| {
120-
serial.serialize(&ErrorResponse {
120+
serial.serialize(ErrorResponse {
121121
id,
122122
error: ResponseError {
123123
code: 0,
@@ -131,7 +131,7 @@ impl<S: Serialization, C: Send + Sync + 'static> RpcMethodBuilder<S, C> {
131131
match callback(param.params, &context) {
132132
Ok(result) => id.map(|id| serial.serialize(&SuccessResponse { id, result })),
133133
Err(err) => id.map(|id| {
134-
serial.serialize(&ErrorResponse {
134+
serial.serialize(ErrorResponse {
135135
id,
136136
error: ResponseError {
137137
code: -1,
@@ -161,7 +161,7 @@ impl<S: Serialization, C: Send + Sync + 'static> RpcMethodBuilder<S, C> {
161161
Ok(p) => p,
162162
Err(err) => {
163163
return future::ready(id.map(|id| {
164-
serial.serialize(&ErrorResponse {
164+
serial.serialize(ErrorResponse {
165165
id,
166166
error: ResponseError {
167167
code: 0,
@@ -182,7 +182,7 @@ impl<S: Serialization, C: Send + Sync + 'static> RpcMethodBuilder<S, C> {
182182
id.map(|id| serial.serialize(&SuccessResponse { id, result }))
183183
}
184184
Err(err) => id.map(|id| {
185-
serial.serialize(&ErrorResponse {
185+
serial.serialize(ErrorResponse {
186186
id,
187187
error: ResponseError {
188188
code: -1,
@@ -222,7 +222,7 @@ impl<S: Serialization, C: Send + Sync + 'static> RpcMethodBuilder<S, C> {
222222
return (
223223
None,
224224
future::ready(id.map(|id| {
225-
serial.serialize(&ErrorResponse {
225+
serial.serialize(ErrorResponse {
226226
id,
227227
error: ResponseError {
228228
code: 0,
@@ -255,7 +255,7 @@ impl<S: Serialization, C: Send + Sync + 'static> RpcMethodBuilder<S, C> {
255255
match callback(servers, param.params, context).await {
256256
Ok(r) => id.map(|id| serial.serialize(&SuccessResponse { id, result: r })),
257257
Err(err) => id.map(|id| {
258-
serial.serialize(&ErrorResponse {
258+
serial.serialize(ErrorResponse {
259259
id,
260260
error: ResponseError {
261261
code: -1,
@@ -427,7 +427,7 @@ impl<S: Serialization, C: Send + Sync> RpcDispatcher<S, C> {
427427
Some(Method::Async(callback)) => MaybeSync::Future(callback(id, body)),
428428
Some(Method::Duplex(callback)) => MaybeSync::Stream(callback(id, body)),
429429
None => MaybeSync::Sync(id.map(|id| {
430-
self.serializer.serialize(&ErrorResponse {
430+
self.serializer.serialize(ErrorResponse {
431431
id,
432432
error: ResponseError {
433433
code: -1,

cli/src/tunnels/code_server.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,17 @@ impl<'a> ServerBuilder<'a> {
566566
}
567567

568568
fn get_base_command(&self) -> Command {
569+
#[cfg(not(windows))]
569570
let mut cmd = Command::new(&self.server_paths.executable);
571+
#[cfg(windows)]
572+
let mut cmd = {
573+
let mut cmd = Command::new("cmd");
574+
cmd.arg("/Q");
575+
cmd.arg("/C");
576+
cmd.arg(&self.server_paths.executable);
577+
cmd
578+
};
579+
570580
cmd.stdin(std::process::Stdio::null())
571581
.args(self.server_params.code_server_args.command_arguments());
572582
cmd

cli/src/tunnels/dev_tunnels.rs

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,9 @@ impl DevTunnels {
275275

276276
/// Renames the current tunnel to the new name.
277277
pub async fn rename_tunnel(&mut self, name: &str) -> Result<(), AnyError> {
278-
self.update_tunnel_name(None, name).await.map(|_| ())
278+
self.update_tunnel_name(self.launcher_tunnel.load(), name)
279+
.await
280+
.map(|_| ())
279281
}
280282

281283
/// Updates the name of the existing persisted tunnel to the new name.
@@ -286,28 +288,34 @@ impl DevTunnels {
286288
name: &str,
287289
) -> Result<(Tunnel, PersistedTunnel), AnyError> {
288290
let name = name.to_ascii_lowercase();
289-
self.check_is_name_free(&name).await?;
290-
291-
debug!(self.log, "Tunnel name changed, applying updates...");
292291

293292
let (mut full_tunnel, mut persisted, is_new) = match persisted {
294293
Some(persisted) => {
294+
debug!(
295+
self.log,
296+
"Found a persisted tunnel, seeing if the name matches..."
297+
);
295298
self.get_or_create_tunnel(persisted, Some(&name), NO_REQUEST_OPTIONS)
296299
.await
297300
}
298-
None => self
299-
.create_tunnel(&name, NO_REQUEST_OPTIONS)
300-
.await
301-
.map(|(pt, t)| (t, pt, true)),
301+
None => {
302+
debug!(self.log, "Creating a new tunnel with the requested name");
303+
self.create_tunnel(&name, NO_REQUEST_OPTIONS)
304+
.await
305+
.map(|(pt, t)| (t, pt, true))
306+
}
302307
}?;
303308

304-
if is_new {
309+
let desired_tags = self.get_tags(&name);
310+
if is_new || vec_eq_as_set(&full_tunnel.tags, &desired_tags) {
305311
return Ok((full_tunnel, persisted));
306312
}
307313

308-
full_tunnel.tags = self.get_tags(&name);
314+
debug!(self.log, "Tunnel name changed, applying updates...");
309315

310-
let new_tunnel = spanf!(
316+
full_tunnel.tags = desired_tags;
317+
318+
let updated_tunnel = spanf!(
311319
self.log,
312320
self.log.span("dev-tunnel.tag.update"),
313321
self.client.update_tunnel(&full_tunnel, NO_REQUEST_OPTIONS)
@@ -317,7 +325,7 @@ impl DevTunnels {
317325
persisted.name = name;
318326
self.launcher_tunnel.save(Some(persisted.clone()))?;
319327

320-
Ok((new_tunnel, persisted))
328+
Ok((updated_tunnel, persisted))
321329
}
322330

323331
/// Gets the persisted tunnel from the service, or creates a new one.
@@ -443,6 +451,8 @@ impl DevTunnels {
443451
) -> Result<(PersistedTunnel, Tunnel), AnyError> {
444452
info!(self.log, "Creating tunnel with the name: {}", name);
445453

454+
self.check_is_name_free(name).await?;
455+
446456
let mut tried_recycle = false;
447457

448458
let new_tunnel = Tunnel {
@@ -527,7 +537,7 @@ impl DevTunnels {
527537
options: &TunnelRequestOptions,
528538
) -> Result<Tunnel, AnyError> {
529539
let new_tags = self.get_tags(name);
530-
if vec_eq_unsorted(&tunnel.tags, &new_tags) {
540+
if vec_eq_as_set(&tunnel.tags, &new_tags) {
531541
return Ok(tunnel);
532542
}
533543

@@ -610,7 +620,7 @@ impl DevTunnels {
610620
}
611621

612622
async fn check_is_name_free(&mut self, name: &str) -> Result<(), AnyError> {
613-
let existing = spanf!(
623+
let existing: Vec<Tunnel> = spanf!(
614624
self.log,
615625
self.log.span("dev-tunnel.rename.search"),
616626
self.client.list_all_tunnels(&TunnelRequestOptions {
@@ -998,7 +1008,7 @@ fn clean_hostname_for_tunnel(hostname: &str) -> String {
9981008
}
9991009
}
10001010

1001-
fn vec_eq_unsorted(a: &[String], b: &[String]) -> bool {
1011+
fn vec_eq_as_set(a: &[String], b: &[String]) -> bool {
10021012
if a.len() != b.len() {
10031013
return false;
10041014
}

cli/src/tunnels/service_windows.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ impl CliServiceManager for WindowsService {
7878
cmd.stderr(Stdio::null());
7979
cmd.stdout(Stdio::null());
8080
cmd.stdin(Stdio::null());
81+
cmd.creation_flags(CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS);
8182
cmd.spawn()
8283
.map_err(|e| wrapdbg(e, "error starting service"))?;
8384

@@ -121,8 +122,12 @@ impl CliServiceManager for WindowsService {
121122

122123
async fn unregister(&self) -> Result<(), AnyError> {
123124
let key = WindowsService::open_key()?;
124-
key.delete_value(TUNNEL_ACTIVITY_NAME)
125-
.map_err(|e| AnyError::from(wrap(e, "error deleting registry key")))?;
125+
match key.delete_value(TUNNEL_ACTIVITY_NAME) {
126+
Ok(_) => {}
127+
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
128+
Err(e) => return Err(wrap(e, "error deleting registry key").into()),
129+
}
130+
126131
info!(self.log, "Tunnel service uninstalled");
127132

128133
let r = do_single_rpc_call::<_, ()>(

extensions/typescript-language-features/src/languageFeatures/util/textRendering.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,13 @@ function getTagBodyText(
4949
return '```\n' + text + '\n```';
5050
}
5151

52-
const text = convertLinkTags(tag.text, filePathConverter);
52+
let text = convertLinkTags(tag.text, filePathConverter);
5353
switch (tag.name) {
5454
case 'example': {
55+
// Example text does not support `{@link}` as it is considered code.
56+
// TODO: should we support it if it appears outside of an explicit code block?
57+
text = asPlainText(tag.text);
58+
5559
// check for caption tags, fix for #79704
5660
const captionTagMatches = text.match(/<caption>(.*?)<\/caption>\s*(\r\n|\n)/);
5761
if (captionTagMatches && captionTagMatches.index === 0) {
@@ -132,6 +136,13 @@ function getTagBody(tag: Proto.JSDocTagInfo, filePathConverter: IFilePathToResou
132136
return (convertLinkTags(tag.text, filePathConverter)).split(/^(\S+)\s*-?\s*/);
133137
}
134138

139+
function asPlainText(parts: readonly Proto.SymbolDisplayPart[] | string): string {
140+
if (typeof parts === 'string') {
141+
return parts;
142+
}
143+
return parts.map(part => part.text).join('');
144+
}
145+
135146
export function asPlainTextWithLinks(
136147
parts: readonly Proto.SymbolDisplayPart[] | string,
137148
filePathConverter: IFilePathToResourceConverter,

extensions/typescript-language-features/src/test/unit/textRendering.test.ts

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const noopToResource: IFilePathToResourceConverter = {
1414
};
1515

1616
suite('typescript.previewer', () => {
17-
test('Should ignore hyphens after a param tag', async () => {
17+
test('Should ignore hyphens after a param tag', () => {
1818
assert.strictEqual(
1919
tagsToMarkdown([
2020
{
@@ -25,7 +25,7 @@ suite('typescript.previewer', () => {
2525
'*@param* `a` — b');
2626
});
2727

28-
test('Should parse url jsdoc @link', async () => {
28+
test('Should parse url jsdoc @link', () => {
2929
assert.strictEqual(
3030
documentationToMarkdown(
3131
'x {@link http://www.example.com/foo} y {@link https://api.jquery.com/bind/#bind-eventType-eventData-handler} z',
@@ -35,7 +35,7 @@ suite('typescript.previewer', () => {
3535
'x [http://www.example.com/foo](http://www.example.com/foo) y [https://api.jquery.com/bind/#bind-eventType-eventData-handler](https://api.jquery.com/bind/#bind-eventType-eventData-handler) z');
3636
});
3737

38-
test('Should parse url jsdoc @link with text', async () => {
38+
test('Should parse url jsdoc @link with text', () => {
3939
assert.strictEqual(
4040
documentationToMarkdown(
4141
'x {@link http://www.example.com/foo abc xyz} y {@link http://www.example.com/bar|b a z} z',
@@ -45,7 +45,7 @@ suite('typescript.previewer', () => {
4545
'x [abc xyz](http://www.example.com/foo) y [b a z](http://www.example.com/bar) z');
4646
});
4747

48-
test('Should treat @linkcode jsdocs links as monospace', async () => {
48+
test('Should treat @linkcode jsdocs links as monospace', () => {
4949
assert.strictEqual(
5050
documentationToMarkdown(
5151
'x {@linkcode http://www.example.com/foo} y {@linkplain http://www.example.com/bar} z',
@@ -55,7 +55,7 @@ suite('typescript.previewer', () => {
5555
'x [`http://www.example.com/foo`](http://www.example.com/foo) y [http://www.example.com/bar](http://www.example.com/bar) z');
5656
});
5757

58-
test('Should parse url jsdoc @link in param tag', async () => {
58+
test('Should parse url jsdoc @link in param tag', () => {
5959
assert.strictEqual(
6060
tagsToMarkdown([
6161
{
@@ -66,7 +66,7 @@ suite('typescript.previewer', () => {
6666
'*@param* `a` — x [abc xyz](http://www.example.com/foo) y [b a z](http://www.example.com/bar) z');
6767
});
6868

69-
test('Should ignore unclosed jsdocs @link', async () => {
69+
test('Should ignore unclosed jsdocs @link', () => {
7070
assert.strictEqual(
7171
documentationToMarkdown(
7272
'x {@link http://www.example.com/foo y {@link http://www.example.com/bar bar} z',
@@ -76,7 +76,7 @@ suite('typescript.previewer', () => {
7676
'x {@link http://www.example.com/foo y [bar](http://www.example.com/bar) z');
7777
});
7878

79-
test('Should support non-ascii characters in parameter name (#90108)', async () => {
79+
test('Should support non-ascii characters in parameter name (#90108)', () => {
8080
assert.strictEqual(
8181
tagsToMarkdown([
8282
{
@@ -135,7 +135,35 @@ suite('typescript.previewer', () => {
135135
);
136136
});
137137

138-
test('Should render @linkcode symbol name as code', async () => {
138+
test('Should not render @link inside of @example #187768', () => {
139+
assert.strictEqual(
140+
tagsToMarkdown([
141+
{
142+
"name": "example",
143+
"text": [
144+
{
145+
"text": "1 + 1 ",
146+
"kind": "text"
147+
},
148+
{
149+
"text": "{@link ",
150+
"kind": "link"
151+
},
152+
{
153+
"text": "foo",
154+
"kind": "linkName"
155+
},
156+
{
157+
"text": "}",
158+
"kind": "link"
159+
}
160+
]
161+
}
162+
], noopToResource),
163+
'*@example* \n```\n1 + 1 {@link foo}\n```');
164+
});
165+
166+
test('Should render @linkcode symbol name as code', () => {
139167
assert.strictEqual(
140168
asPlainTextWithLinks([
141169
{ "text": "a ", "kind": "text" },
@@ -155,7 +183,7 @@ suite('typescript.previewer', () => {
155183
'a [`dog`](command:_typescript.openJsDocLink?%5B%7B%22file%22%3A%7B%22path%22%3A%22%2Fpath%2Ffile.ts%22%2C%22scheme%22%3A%22file%22%7D%2C%22position%22%3A%7B%22line%22%3A6%2C%22character%22%3A4%7D%7D%5D) b');
156184
});
157185

158-
test('Should render @linkcode text as code', async () => {
186+
test('Should render @linkcode text as code', () => {
159187
assert.strictEqual(
160188
asPlainTextWithLinks([
161189
{ "text": "a ", "kind": "text" },

0 commit comments

Comments
 (0)