├── .config └── tsaoptions.json ├── .editorconfig ├── .eslintrc.json ├── .gitattributes ├── .gitignore ├── .npmrc ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── CHANGELOG.md ├── CODE-OF-CONDUCT.md ├── LICENSE ├── README.md ├── azure-pipelines.yml ├── build.cmd ├── dotnet-logo.png ├── media ├── build-an-app.md ├── csharp-notebooks.gif ├── install-sdk.md ├── learn-dotnet-website.png ├── new-to-vscode.md ├── notebooks.md ├── search.gif ├── vscode-intro-videos.png └── where-to-start.md ├── misc └── Getting started with .NET.dib ├── package-lock.json ├── package.json ├── src ├── commands │ └── index.ts ├── exp │ └── index.ts ├── extension.ts ├── getting-started │ └── index.ts ├── misc │ └── index.ts └── utils │ ├── command.ts │ ├── extension.ts │ ├── idle.ts │ ├── index.ts │ └── scheduler.ts ├── tsconfig.json ├── types └── vscode-dotnet-runtime.d.ts └── webpack.config.js /.config/tsaoptions.json: -------------------------------------------------------------------------------- 1 | { 2 | "instanceUrl": "https://devdiv.visualstudio.com/", 3 | "template": "TFSDEVDIV", 4 | "projectName": "DEVDIV", 5 | "areaPath": "DevDiv\\NET Developer Experience\\Productivity", 6 | "iterationPath": "DevDiv", 7 | "notificationAliases": [ "mlinfraswat@microsoft.com" ], 8 | "repositoryName":"vscode-dotnet-pack", 9 | "codebaseName": "vscode-dotnet-pack" 10 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{js,ts}] 4 | indent_style = space 5 | indent_size = 2 6 | tab_width = 2 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint", 10 | "jsdoc" 11 | ], 12 | "rules": { 13 | "constructor-super": "warn", 14 | "curly": "warn", 15 | "eqeqeq": "warn", 16 | "no-buffer-constructor": "warn", 17 | "no-caller": "warn", 18 | "no-debugger": "warn", 19 | "no-duplicate-case": "warn", 20 | "no-duplicate-imports": "warn", 21 | "no-eval": "warn", 22 | "no-extra-semi": "warn", 23 | "no-new-wrappers": "warn", 24 | "no-redeclare": "off", 25 | "no-sparse-arrays": "warn", 26 | "no-throw-literal": "warn", 27 | "no-unsafe-finally": "warn", 28 | "no-unused-expressions": [ 29 | "warn", 30 | { 31 | "allowTernary": true 32 | } 33 | ], 34 | "no-unused-labels": "warn", 35 | "no-restricted-globals": [ 36 | "warn", 37 | "name", 38 | "length", 39 | "event", 40 | "closed", 41 | "external", 42 | "status", 43 | "origin", 44 | "orientation", 45 | "context" 46 | ], // non-complete list of globals that are easy to access unintentionally 47 | "no-var": "warn", 48 | "jsdoc/no-types": "warn", 49 | "semi": "off", 50 | "@typescript-eslint/semi": "warn", 51 | "@typescript-eslint/naming-convention": [ 52 | "warn", 53 | { 54 | "selector": "class", 55 | "format": [ 56 | "PascalCase" 57 | ] 58 | } 59 | ] 60 | } 61 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to: 3 | # automatically normalize line endings on check-in, and 4 | # convert to Windows-style line endings on check-out 5 | ############################################################################### 6 | * text=auto encoding=UTF-8 7 | *.sh text eol=lf 8 | 9 | ############################################################################### 10 | # Set file behavior to: 11 | # treat as text 12 | ############################################################################### 13 | *.cmd text 14 | *.json text 15 | *.md text 16 | 17 | ############################################################################### 18 | # Set file behavior to: 19 | # treat as binary 20 | ############################################################################### 21 | *.png binary 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | out/ 61 | 62 | .DS_Store 63 | 64 | .vscode-test 65 | 66 | *.vsix 67 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | 2 | # Auto generated file from Gardener Plugin CentralFeedServiceAdoptionPlugin 3 | registry=https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ], 16 | "outFiles": [ 17 | "${workspaceFolder}/out/**/*.js" 18 | ], 19 | "preLaunchTask": "npm: watch" 20 | }, 21 | { 22 | "name": "Extension Tests", 23 | "type": "extensionHost", 24 | "request": "launch", 25 | "runtimeExecutable": "${execPath}", 26 | "args": [ 27 | "--extensionDevelopmentPath=${workspaceFolder}", 28 | "--extensionTestsPath=${workspaceFolder}/out/test" 29 | ], 30 | "outFiles": [ 31 | "${workspaceFolder}/out/test/**/*.js" 32 | ], 33 | "preLaunchTask": "npm: watch" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | "eslint.alwaysShowStatus": true 10 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": { 10 | "owner": "typescript", 11 | "pattern":[ 12 | { 13 | "regexp": "\\[tsl\\] ERROR", 14 | "file": 1, 15 | "location": 2, 16 | "message": 3 17 | } 18 | ], 19 | "background": { 20 | "activeOnStart": true, 21 | "beginsPattern": "Compilation \\w+ starting…", 22 | "endsPattern": "Compilation\\s+finished" 23 | } 24 | }, 25 | "isBackground": true, 26 | "presentation": { 27 | "reveal": "never" 28 | }, 29 | "group": { 30 | "kind": "build", 31 | "isDefault": true 32 | } 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.0.13 4 | - [Upgrade extension pack to depend on .NET 8](https://github.com/dotnet/vscode-dotnet-pack/pull/406) 5 | 6 | ## 1.0.12 7 | - [Update readme and tags](https://github.com/dotnet/vscode-dotnet-pack/pull/404) 8 | 9 | ## 1.0.11 10 | - [Update commands and activation events](https://github.com/dotnet/vscode-dotnet-pack/pull/399) 11 | 12 | ## 1.0.10 13 | - [Upgrade extension pack to depend on .NET 7](https://github.com/dotnet/vscode-dotnet-pack/pull/393) 14 | 15 | ## 1.0.9 16 | - [Add walkthrough](https://github.com/dotnet/vscode-dotnet-pack/pull/101) 17 | - [Remove unused dependencies](https://github.com/dotnet/vscode-dotnet-pack/pull/59) 18 | - [Add test plan for release validation.](https://github.com/dotnet/vscode-dotnet-pack/pull/58) 19 | 20 | ## 1.0.8 (February 8th, 2022) 21 | - [Add uri handler for getting started notebook](https://github.com/dotnet/vscode-dotnet-pack/pull/42) 22 | 23 | ## 1.0.7 (February 3rd, 2022) 24 | - [Don't directly activate .NET Interactive](https://github.com/dotnet/vscode-dotnet-pack/pull/39) 25 | 26 | ## 1.0.6 (January 27th, 2022) 27 | - [Call `acquire` if `acquireStatus` fails](https://github.com/dotnet/vscode-dotnet-pack/pull/35) 28 | 29 | ## 1.0.5 (January 11th, 2022) 30 | - [Explicitly install the Jupyter extension](https://github.com/dotnet/vscode-dotnet-pack/pull/29) 31 | - [Update extension to depend on .NET 6](https://github.com/dotnet/vscode-dotnet-pack/pull/24) 32 | 33 | ## 1.0.4 (June 14th, 2021) 34 | - [Bump version to 1.0.4](https://github.com/dotnet/vscode-dotnet-pack/commit/572cf87b361dd69624cfba55ebf6733b101b30f2) 35 | - [Sniff for dotnet-sdk](https://github.com/dotnet/vscode-dotnet-pack/pull/20) 36 | 37 | ## 1.0.3 (May 10th, 2021) 38 | First public release 39 | 40 | 41 | -------------------------------------------------------------------------------- /CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | This project has adopted the code of conduct defined by the Contributor Covenant 4 | to clarify expected behavior in our community. 5 | 6 | For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct). 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) .NET Foundation and Contributors 4 | 5 | All rights reserved. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # .NET Extension Pack 2 | 3 | The .NET Extension Pack is the ultimate collection of extensions for working with .NET in VS Code. 4 | 5 | ## C# for Visual Studio Code (powered by OmniSharp) 6 | 7 | [C# extension for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) provides the following features inside VS Code: 8 | 9 | - Lightweight development tools for [.NET Core](https://dotnet.github.io). 10 | - Great C# editing support, including Syntax Highlighting, IntelliSense, Go to Definition, Find All References, etc. 11 | - Debugging support for .NET Core (CoreCLR). NOTE: Mono debugging is not supported. Desktop CLR debugging has [limited support](https://github.com/OmniSharp/omnisharp-vscode/wiki/Desktop-.NET-Framework). 12 | - Support for project.json and csproj projects on Windows, macOS and Linux. 13 | 14 | The C# extension is powered by [OmniSharp](https://github.com/OmniSharp/omnisharp-roslyn). 15 | 16 | ## .NET Interactive Notebooks 17 | 18 | [Polyglot Notebooks extension for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.dotnet-interactive-vscode) provides support for using Polyglot Notebooks in a Visual Studio Code notebook. Polyglot Notebooks takes the power of .NET and embeds it into *your* interactive experiences. Share code, explore data, write, and learn across your apps in ways you couldn't before. 19 | 20 | - [Notebooks](#notebooks-with-net): Jupyter, nteract, and Visual Studio Code 21 | - [Code bots](https://github.com/CodeConversations/CodeConversations) 22 | - Devices like [Raspberry Pi](https://www.raspberrypi.org/) 23 | - Embeddable script engines 24 | - REPLs 25 | 26 | ## Ionide-VSCode: FSharp 27 | 28 | [Ionide FSharp extension for Visual Studio Code](https://marketplace.visualstudio.com/items/Ionide.Ionide-fsharp) provides support for enhanced F# Language Features for Visual Studio Code. 29 | 30 | - Syntax highlighting 31 | - Auto completions 32 | - Error highlighting, error list, and quick fixes based on errors 33 | - Tooltips 34 | - Method parameter hints 35 | - Go to Definition 36 | - Peek Definition 37 | - Find all references 38 | - Highlighting usages 39 | - Rename 40 | - Show symbols in file 41 | - Find symbol in workspace 42 | - Show signature in status bar 43 | - Show signature as CodeLens / LineLens 44 | - Go to MSDN help 45 | - Add `open NAMESPACE` for symbol 46 | - Match case generator 47 | - Go to #load reference 48 | - Generate comment for the symbol 49 | - Integration with F# Interactive 50 | - Integration with Forge (Project scaffolding and modification) 51 | - Integration with FSharpLint (additional hints and quick fixes) 52 | - Integration with MSBuild (Build, Rebuild, Clean project) 53 | - Solution / project explorer 54 | - And more... 55 | 56 | ## Installation 57 | 58 | By installing this extension you will install all of the extensions listed above. 59 | 60 | You can uninstall all the extensions by uninstalling this extension pack. 61 | 62 | ## Contributing 63 | 64 | Got a suggestion for the .NET Extension Pack? Submit a new issue and a PR with an updated package.json and README.md and we'll take a look! 65 | 66 | ## Contribution License Agreement 67 | 68 | By signing the [CLA](https://cla.dotnetfoundation.org/), the community is free to use your contribution to [.NET Foundation](http://www.dotnetfoundation.org) projects. 69 | 70 | ## License 71 | 72 | Copyright © .NET Foundation, and contributors. 73 | 74 | The source code to this extension is available on [https://github.com/microsoft/vscode-dotnet-pack](https://github.com/microsoft/vscode-dotnet-pack) and licensed under the [MIT license](LICENSE.txt). 75 | 76 | ## Code of Conduct 77 | 78 | This project has adopted the code of conduct defined by the [Contributor Covenant](http://contributor-covenant.org/) 79 | to clarify expected behavior in our community. 80 | For more information see the [.NET Foundation Code of Conduct](http://www.dotnetfoundation.org/code-of-conduct). 81 | 82 | ## .NET Foundation 83 | 84 | This project is supported by the [.NET Foundation](http://www.dotnetfoundation.org). 85 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: DotnetExtensionPackCI 3 | timeoutInMinutes: 30 4 | cancelTimeoutInMinutes: 2 5 | variables: 6 | - ${{ if and(notin(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.SourceBranch'], 'refs/heads/main')) }}: 7 | # Force CodeQL enabled so it may be run on any branch 8 | - name: Codeql.Enabled 9 | value: true 10 | # Do not let CodeQL 3000 Extension gate scan frequency 11 | - name: Codeql.Cadence 12 | value: 0 13 | - name: Codeql.TSAEnabled 14 | value: true 15 | pool: 16 | vmImage: 'windows-2022' 17 | 18 | steps: 19 | - task: NodeTool@0 20 | inputs: 21 | versionSpec: '14.x' 22 | displayName: 'Install Node.js' 23 | 24 | - ${{ if and(notin(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.SourceBranch'], 'refs/heads/main')) }}: 25 | - task: UseDotNet@2 26 | - task: CodeQL3000Init@0 27 | displayName: CodeQL Initialize 28 | 29 | - script: | 30 | npm ci 31 | displayName: 'npm install' 32 | 33 | - task: CmdLine@2 34 | displayName: 'Build .NET extension pack' 35 | inputs: 36 | script: | 37 | echo Building .NET extension pack vsix... 38 | npx vsce@latest package 39 | 40 | - ${{ if and(notin(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.SourceBranch'], 'refs/heads/main')) }}: 41 | - task: CodeQL3000Finalize@0 42 | displayName: CodeQL Finalize 43 | 44 | - task: CopyFiles@2 45 | inputs: 46 | Contents: '*.vsix' 47 | TargetFolder: '$(Build.ArtifactStagingDirectory)' 48 | 49 | - task: PublishBuildArtifacts@1 50 | inputs: 51 | PathtoPublish: '$(Build.ArtifactStagingDirectory)' 52 | ArtifactName: 'drop' 53 | publishLocation: 'Container' 54 | -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | npx vsce@latest package -------------------------------------------------------------------------------- /dotnet-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/vscode-dotnet-pack/6d8c7021ac4db448933b398aa27c009ecfddef31/dotnet-logo.png -------------------------------------------------------------------------------- /media/build-an-app.md: -------------------------------------------------------------------------------- 1 | ![A screenshot of the Microsoft learn dotnet website.](learn-dotnet-website.png) 2 | -------------------------------------------------------------------------------- /media/csharp-notebooks.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/vscode-dotnet-pack/6d8c7021ac4db448933b398aa27c009ecfddef31/media/csharp-notebooks.gif -------------------------------------------------------------------------------- /media/install-sdk.md: -------------------------------------------------------------------------------- 1 | ## Install .NET SDK 2 | 3 | If you don't have .NET SDK installed on your machine, you can install it by clicking on __Install .NET SDK__. 4 | 5 | To verify it's installed, [create a new terminal](command:workbench.action.terminal.new) and try running the following command: 6 | 7 | ``` 8 | dotnet --version 9 | ``` 10 | 11 | You should see the version of the .NET SDK that you have installed. -------------------------------------------------------------------------------- /media/learn-dotnet-website.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/vscode-dotnet-pack/6d8c7021ac4db448933b398aa27c009ecfddef31/media/learn-dotnet-website.png -------------------------------------------------------------------------------- /media/new-to-vscode.md: -------------------------------------------------------------------------------- 1 | ![A screenshot of the VS Code introductory videos website.](vscode-intro-videos.png) 2 | 3 | -------------------------------------------------------------------------------- /media/notebooks.md: -------------------------------------------------------------------------------- 1 | ![A gif of using the command palette](search.gif) 2 | -------------------------------------------------------------------------------- /media/search.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/vscode-dotnet-pack/6d8c7021ac4db448933b398aa27c009ecfddef31/media/search.gif -------------------------------------------------------------------------------- /media/vscode-intro-videos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/vscode-dotnet-pack/6d8c7021ac4db448933b398aa27c009ecfddef31/media/vscode-intro-videos.png -------------------------------------------------------------------------------- /media/where-to-start.md: -------------------------------------------------------------------------------- 1 | ![A gif showing how to find csharp notebooks](csharp-notebooks.gif) -------------------------------------------------------------------------------- /misc/Getting started with .NET.dib: -------------------------------------------------------------------------------- 1 | #!markdown 2 | 3 | # Get Started with C# for Beginners 4 | 5 | Welcome to .NET Interactive and your first C# notebook. C# is an programming language that you can use to make many different types of programs including websites, games, and mobile applications. Let's explore some of the basics of using C# in this notebook and write your first .NET code! 6 | 7 | Just click the run icon in a code cell to execute it, or hit the key command. 8 | 9 | #!markdown 10 | 11 | ## C# Syntax Basics 12 | 13 | C# allows you to insert as much space as you would like between commands that you write. You can use tabs or spaces to format your C# code to make it easier for us humans to read. Complete lines of code, or **statements**, need to end with a semicolon so that the C# **compiler** knows that we have completed giving it an instruction. 14 | 15 | A **compiler** turns our C# statements into a file that a computer can execute. 16 | 17 | Let's write our first line of C# code, a simple "hello world" statement in C#: 18 | 19 | #!csharp 20 | 21 | Console.WriteLine("Hello, world!"); 22 | 23 | #!markdown 24 | 25 | Let's review what happened there. **Console.WriteLine** is an instruction that tells C# to write the contents of the parenthesis **( )**. We include some text, referred to as a **string** enclosed in double-quotes that we would like C# to write for us. 26 | 27 | #!markdown 28 | 29 | ## Introducing Variables 30 | 31 | We can instruct C# to store values in memory using **variables**. A variable can store a value that we **assign** to it using the `=` operator. 32 | 33 | Let's define a variable of type `string` called `aFriend` and store the name "Bill". 34 | 35 | #!csharp 36 | 37 | string aFriend = "Bill"; 38 | Console.WriteLine(aFriend); 39 | 40 | #!markdown 41 | 42 | You can also re-assign different values to a variable, like so: 43 | 44 | #!csharp 45 | 46 | aFriend = "Maira"; 47 | Console.WriteLine(aFriend); 48 | 49 | #!markdown 50 | 51 | ## Work with strings 52 | 53 | The data type used above is called a `string`. It's used for textual data. 54 | 55 | You can also combine strings. In this case, we'll use `+` to combine two strings: 56 | 57 | #!csharp 58 | 59 | Console.WriteLine("Hello " + aFriend); 60 | 61 | #!markdown 62 | 63 | When working with strings, you can also use [String Interpolation](https://docs.microsoft.com/dotnet/csharp/language-reference/tokens/interpolated) to combine values into a string: 64 | 65 | #!csharp 66 | 67 | Console.WriteLine($"Hello {aFriend}"); 68 | 69 | #!markdown 70 | 71 | You're not limited to a single variable between the curly braces when using String Interpolation: 72 | 73 | #!csharp 74 | 75 | string firstFriend = "Maria"; 76 | string secondFriend = "Sage"; 77 | Console.WriteLine($"My friends are {firstFriend} and {secondFriend}"); 78 | 79 | #!markdown 80 | 81 | As you explore more with strings, you'll find that strings are more than a collection of letters. You can find the length of a string using `Length`. `Length` is a property of a string and it returns the number of characters in that string: 82 | 83 | #!csharp 84 | 85 | Console.WriteLine($"The name {firstFriend} has {firstFriend.Length} letters."); 86 | Console.WriteLine($"The name {secondFriend} has {secondFriend.Length} letters."); 87 | 88 | #!markdown 89 | 90 | ## Do more with strings 91 | 92 | You've been using a *method*, `Console.WriteLine`, to print messages. A method is a block of code that implements some action. It has a name, so you can access it. 93 | 94 | Suppose your strings have leading or trailing spaces that you don't want to display. You want to **trim** the spaces from the strings. The `Trim` method and related methods `TrimStart` and `TrimEnd` do that work. You can just use those methods to remove leading and trailing spaces. 95 | 96 | #!csharp 97 | 98 | string greeting = " Hello World! "; 99 | Console.WriteLine($"[{greeting}]"); 100 | 101 | string trimmedGreeting = greeting.TrimStart(); 102 | Console.WriteLine($"[{trimmedGreeting}]"); 103 | 104 | trimmedGreeting = greeting.TrimEnd(); 105 | Console.WriteLine($"[{trimmedGreeting}]"); 106 | 107 | trimmedGreeting = greeting.Trim(); 108 | Console.WriteLine($"[{trimmedGreeting}]"); 109 | 110 | #!markdown 111 | 112 | There are other methods available to work with a string. For example, you've probably used a search and replace command in an editor or word processor before. The `Replace` method does something similar in a string. It searches for a substring and replaces it with different text. The `Replace` method takes two parameters. These are the strings between the parentheses. The first string is the text to search for. The second string is the text to replace it with: 113 | 114 | #!csharp 115 | 116 | string sayHello = "Hello World!"; 117 | Console.WriteLine(sayHello); 118 | sayHello = sayHello.Replace("Hello", "Greetings"); 119 | Console.WriteLine(sayHello); 120 | 121 | #!markdown 122 | 123 | Two other useful methods make a string ALL CAPS or all lower case: 124 | 125 | #!csharp 126 | 127 | Console.WriteLine(sayHello.ToUpper()); 128 | Console.WriteLine(sayHello.ToLower()); 129 | 130 | #!markdown 131 | 132 | ## Search strings 133 | 134 | The other part of a search and replace operation is to find text in a string. You can use the `Contains` method for searching. It tells you if a string contains a substring inside it: 135 | 136 | #!csharp 137 | 138 | string songLyrics = "You say goodbye, and I say hello"; 139 | Console.WriteLine(songLyrics.Contains("goodbye")); 140 | Console.WriteLine(songLyrics.Contains("greetings")); 141 | 142 | #!markdown 143 | 144 | ## Comments 145 | 146 | You can write comments by using the two forward-slash characters to indicate everything after them is a comment. 147 | 148 | #!csharp 149 | 150 | // This is a comment 151 | 152 | #!markdown 153 | 154 | The below script needs to be able to find the current output cell; this is an easy method to get it. 155 | 156 | You can create comments that span multiple lines by using slash asterisk fencing like the following: 157 | 158 | #!csharp 159 | 160 | /* 161 | This is a multi-line comment 162 | 163 | and this is still commented out 164 | */ 165 | 166 | #!markdown 167 | 168 | ## Built-In Variable Types 169 | 170 | Variables can be declared of various **types** and then interacted with. The simplest types in C# are called [Built-In Types](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/built-in-types) 171 | 172 | We define variables using in-memory storage for a type by preceeding the name of the variable we would like to create with the type of the variable we are creating. 173 | 174 | #!csharp 175 | 176 | int i = 10; 177 | double j = 5.5d; 178 | char c = 'C'; 179 | 180 | c 181 | 182 | #!markdown 183 | 184 | ### The var keyword 185 | 186 | Sometimes, its a little cumbersome to declare a variable, assign a value, and have to specify the type before it. C# has built-in type inference and you can use the var keyword to force the compiler to detect the actual type being created and set the variable to the type of the value being assigned. 187 | 188 | #!csharp 189 | 190 | var i = 10; 191 | var someReallyLongVariableName = 9; 192 | var foo = "Something"; 193 | display(someReallyLongVariableName); 194 | 195 | var c = 'C'; 196 | c 197 | 198 | #!markdown 199 | 200 | You can ONLY use the var keyword when creating and assigning the variable in one statement. 201 | 202 | ### Real Literals 203 | 204 | We can declare double, float, and decimal types with simple numeric notation, but we need to force the literal numbers we assign to be the correct type to match the variable type expected. 205 | 206 | To do this, we add a d, f, or m suffix to a number being assigned. Try changing the suffix on the number in the next block and see what types it assigns. 207 | 208 | #!csharp 209 | 210 | var myNumber = 4f; 211 | myNumber.GetType() 212 | 213 | #!markdown 214 | 215 | ## Type Casting 216 | 217 | We can convert a variable between different types in several ways: 218 | 219 | 1. Assign to a variable of a different type 220 | 1. Convert between types by placing the destination type in parenthesis 221 | 222 | #!csharp 223 | 224 | int valueA = 10; 225 | decimal valueB = valueA; // Implicit conversion 226 | 227 | display(valueB); 228 | 229 | decimal valueC = 10; 230 | //int valueD = valueC; // This errors out because int cannot be implicitly converted to by a decimal 231 | int valueD = (int)valueC; // Explicitly convert valueC to int with the (int) modifier 232 | 233 | display(valueD); 234 | 235 | #!markdown 236 | 237 | ## Operators 238 | 239 | Now that we have some basic types and can create variables, it would sure be nice to have them interact with each other. [Operators](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/) can be used to interact with our variables. 240 | 241 | Let's start by declaring two variables, apples and oranges and interact with them using different operators. Try changing some of the values and tinkering with the operators in the following code snippets. 242 | 243 | #!csharp 244 | 245 | var apples = 100m; // Decimal value 246 | var oranges = 30m; // Decimal value 247 | 248 | #!markdown 249 | 250 | Basic arithmetic operators and assignment are available: 251 | 252 | #!csharp 253 | 254 | display(apples + oranges); 255 | 256 | #!csharp 257 | 258 | display(apples - oranges); 259 | 260 | #!csharp 261 | 262 | display(apples * oranges); 263 | 264 | #!csharp 265 | 266 | display(apples += 10); 267 | 268 | display(apples -= 10); 269 | 270 | display(apples *= 10); 271 | 272 | display(apples /= 3m); 273 | 274 | #!markdown 275 | 276 | C# makes the inequality operators available as well, and a test for equality using == 277 | 278 | #!csharp 279 | 280 | display(apples > oranges) 281 | 282 | #!csharp 283 | 284 | display(apples >= oranges) 285 | 286 | #!csharp 287 | 288 | display(apples < oranges) 289 | 290 | #!csharp 291 | 292 | display(apples <= oranges) 293 | 294 | #!csharp 295 | 296 | display(apples == oranges) 297 | 298 | #!csharp 299 | 300 | display(apples != oranges) 301 | 302 | #!markdown 303 | 304 | ## Loops and Conditionals 305 | 306 | Common to every programming language are the concepts of loops or repeated execution of the same block of code and conditional execution of code. These features are typically manifest as the following statements: 307 | 308 | - for 309 | - while 310 | - do 311 | - if 312 | - switch or case 313 | 314 | ### Conditionals 315 | 316 | There are two statement-level conditional interactions in C#: if and switch...case statements. If statements can be combined with any number of else if statements and a single else statement to route code flow and interactions across branches of code. [(Link to official docs)](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/if-else) 317 | 318 | Let's take a look at a simple if statement. 319 | 320 | #!csharp 321 | 322 | var seconds = DateTime.Now.Second; 323 | display("Current seconds: " + seconds); 324 | 325 | // A simple test, are the number of seconds a multiple of 2? 326 | if ( seconds % 2 == 0 ) { 327 | 328 | // Do this thing when seconds are even 329 | display("seconds are even"); 330 | 331 | } 332 | 333 | #!markdown 334 | 335 | The if statement starts with the if keyword and continues with a test in parenthesis. Next, the code to be executed if the test evaluates to true is contained within curly braces { }. The use of braces is optional, as long as the code to be executed is a single line. 336 | 337 | #!csharp 338 | 339 | var seconds = DateTime.Now.Second; 340 | display("Current seconds: " + seconds); 341 | 342 | // One line if statement 343 | if (seconds % 2 == 0) display("Seconds are even"); 344 | 345 | if (seconds % 2 == 1) 346 | display("Seconds are odd"); 347 | 348 | 349 | display("This will always execute, even though it LOOKS LIKE its in the if statement"); 350 | 351 | #!markdown 352 | 353 | Great, if the condition is met we can execute some code. What if we need some more complex branching and potentially apply secondary tests and code if those tests return false? We can start using the else and else if syntax to add these additional branches of code to be executed. 354 | 355 | Let's look a more complex branching scenario: 356 | 357 | #!csharp 358 | 359 | var seconds = DateTime.Now.Second; 360 | display("Current seconds: " + seconds); 361 | 362 | if (seconds % 2 == 0) { 363 | display("Seconds are even"); 364 | } else if (seconds % 3 == 0) { 365 | display("Seconds are a multiple of 3"); 366 | } else if (seconds % 5 == 0) { 367 | display("Seconds are a multiple of 5"); 368 | } else { 369 | display("Seconds are neither even nor a multiple of 3"); 370 | } 371 | 372 | if (seconds % 2 == 0) display("Seconds are even"); 373 | else if (seconds % 3 == 0) display("Seconds are a multiple of 3"); 374 | else if (seconds % 5 == 0) display("Seconds are a multiple of 5"); 375 | else display("Seconds are neither even nor a multiple of 3"); 376 | 377 | #!markdown 378 | 379 | Testing for one condition is fine... but what if we have a compound scenario where we need to test for multiple factors before we determine which branch to take? 380 | 381 | You can chain together conditional tests using the logical OR | and the logical AND & operators. 382 | 383 | #!csharp 384 | 385 | var seconds = DateTime.Now.Second; 386 | // seconds = 7; 387 | display("Current seconds: " + seconds); 388 | 389 | // Test for BOTH multiple of 2 AND a multiple of 3 390 | if (seconds % 2 == 0 & seconds % 3 == 0) { 391 | display("Seconds are even AND a multiple of 3"); 392 | } else if (seconds % 2 == 0) { 393 | display("Seconds are even"); 394 | } else if (seconds % 3 == 0) { 395 | display("Seconds are a multiple of 3"); 396 | 397 | // Test for seconds to be a multiple of 5 OR a multiple of 7 398 | } else if (seconds % 5 == 0 | seconds % 7 == 0) { 399 | display("Seconds are a multiple of 5 OR 7"); 400 | } else { 401 | display("Seconds are neither even nor a multiple of 3"); 402 | } 403 | 404 | #!markdown 405 | 406 | There is another scenario that you will see many developers use to prioritize the compound boolean test inside an if statement, and that is using the 'short circuit' operators && and ||. They're referred to as a 'short circuit' operators because they evaluate the first condition on the left and if necessary evaluate the condition on the right side of the operator. 407 | 408 | The && operator is called the **Conditional Logical AND** operator or referred to as **AndAlso** in Visual Basic. This operator behaves as follows: 409 | 410 | 1. Evaluate the left-side of the operator 411 | 1. IF the left-side evaluates to false, return false and stop processing 412 | 1. ELSE return the result of evaluating the right-side of the operator 413 | 414 | Here's an example: 415 | 416 | #!csharp 417 | 418 | var seconds = DateTime.Now.Second; 419 | display("Current seconds: " + seconds); 420 | 421 | bool MultipleOfThree() { 422 | display("MultipleOfThree was called"); 423 | return seconds % 3 == 0; 424 | } 425 | 426 | if (seconds % 2 == 0 && MultipleOfThree()) { 427 | display("Seconds are even and a multiple of three"); 428 | } 429 | 430 | if (seconds != null && seconds % 2 == 1) { 431 | display("Seconds are odd"); 432 | } 433 | 434 | #!markdown 435 | 436 | In this scenario, if the number of seconds are even then the MultipleOfThree method is executed. If the number of seconds is even and a multiple of three, then it is reported as such. We can also observe that when the number of seconds is even, the MultipleOfThree method is executed because it is reported in the output. 437 | 438 | The || operator is called the **Conditional Logical OR operator** or referred to as the **OrElse** operator by the Visual Basic language. This operator behaves like the following: 439 | 440 | 1. Evaluate the left-side of the operator 441 | 1. IF the left-side evaluates to true, return true and stop processing 442 | 1. ELSE return the result of evaluating the right-side of the operator 443 | 444 | Here's an example: 445 | 446 | #!csharp 447 | 448 | var seconds = DateTime.Now.Second; 449 | // seconds = 6; 450 | display("Current seconds: " + seconds); 451 | 452 | bool MultipleOfThree() { 453 | display("MultipleOfThree was called"); 454 | return seconds % 3 == 0; 455 | } 456 | 457 | if (seconds % 2 == 0 || MultipleOfThree()) { 458 | display("Seconds are even or a multiple of three"); 459 | } 460 | 461 | #!markdown 462 | 463 | ### Switch Statements 464 | 465 | Sometimes we have a LOT of conditions and branches that we want to evaluate and potentially traverse in our code. The [switch statement](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/switch) allows you to configure using the switch, case, break, and default statements the various branches you could potentially step down. 466 | 467 | Use switch (test expression) to perform your test. Then use a series of case (result): statements to provide the various branching code paths to potentially execute. You can allow processing to 'fall out' of one statement into the next, and even provide a default branch at the end to ensure a branch is executed if none of the cases are matched. 468 | 469 | Let's look at a real example: 470 | 471 | #!csharp 472 | 473 | var dayOfTheWeek = DateTime.Now.DayOfWeek; 474 | // dayOfTheWeek = DayOfWeek.Friday; 475 | 476 | switch (dayOfTheWeek) { 477 | case DayOfWeek.Monday: 478 | display("Does somebody have a case of the Mondays?"); 479 | break; 480 | case DayOfWeek.Tuesday: 481 | display("It's TACO TUESDAY at the cafe!"); 482 | break; 483 | case DayOfWeek.Wednesday: 484 | display("Middle of the work-week... almost done!"); 485 | break; 486 | case DayOfWeek.Thursday: 487 | display("Friday is ALMOST HERE!!"); 488 | break; 489 | case DayOfWeek.Friday: 490 | display("The weekend starts.... NOW!"); 491 | break; 492 | case DayOfWeek.Saturday: 493 | display("Relaxing... no school, no work..."); 494 | break; 495 | case DayOfWeek.Sunday: 496 | display("School and work tomorrow? Better have some fun NOW!"); 497 | break; 498 | default: 499 | display("I don't care what day of the week it is... we're on HOLIDAY!"); 500 | break; 501 | } 502 | 503 | #!markdown 504 | 505 | We can add additional tests for case statements using a when clause as well: 506 | 507 | #!csharp 508 | 509 | var dayOfTheWeek = DateTime.Now.DayOfWeek; 510 | var hourOfDay = DateTime.Now.Hour; 511 | 512 | /* Extra conditions to test with */ 513 | dayOfTheWeek = DayOfWeek.Monday; 514 | hourOfDay = 17; 515 | /* */ 516 | 517 | switch (dayOfTheWeek) { 518 | case DayOfWeek.Monday: 519 | case DayOfWeek.Tuesday: 520 | case DayOfWeek.Wednesday: 521 | case DayOfWeek.Thursday: 522 | case DayOfWeek.Friday when hourOfDay < 16: 523 | display("Work work work..."); 524 | break; 525 | case DayOfWeek.Friday when hourOfDay >= 16: 526 | display("The weekend starts.... NOW!"); 527 | break; 528 | case DayOfWeek.Saturday: 529 | case DayOfWeek.Sunday: 530 | display("Relaxing... no school, no work..."); 531 | break; 532 | } 533 | 534 | #!markdown 535 | 536 | ### For Loops 537 | 538 | [For loops](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/for) are a looping statement that allow you to repeat a block of code depending on a counter expression. The for statement takes the general form: 539 | 540 | `for (Initializer; Condition; Iterator) { CODE TO EXECUTE }` 541 | 542 | The Initializer typically initializes a counter variable to be worked with. 543 | 544 | The Condition is a test to be executed at the beginning of each attempt to execute the code block. If the Condition evaluates to true then the code block will be executed. 545 | 546 | The optional Iterator code executes after each loop and typically increments the initialized variable , stepping towards the end value. 547 | 548 | Typical use for the for statement looks similar to the following, where 5 is an arbitrary number to stop counting at. 549 | 550 | ``` 551 | for (var i=0; i<5; i++) { 552 | 553 | } 554 | ``` 555 | 556 | In practice it works like this: 557 | 558 | #!csharp 559 | 560 | for (var counter=0; counter<5; counter++) { 561 | display("Counting " + counter); 562 | } 563 | 564 | #!markdown 565 | 566 | Loops can even count backwards! This is because the iterator expression at the end of the for statement can execute any code. Let's try it with the -= operator: 567 | 568 | #!csharp 569 | 570 | for (var counter=5; counter>0; counter-= 3) { 571 | display("Counting " + counter); 572 | } 573 | 574 | #!markdown 575 | 576 | ### Break Statement in For loops 577 | 578 | If you need to exit a loop and continue processing, you can execute the break statement. 579 | 580 | In the following loop, it is configured to run forever with the counter value starting at 1 and continuing as long as the counter > 0. The break statement will be triggered once the counter crosses 10. 581 | 582 | #!csharp 583 | 584 | for (var counter=1; counter>0; counter++) { 585 | display("Counting " + counter); 586 | 587 | if (counter > 10) break; 588 | 589 | } 590 | 591 | #!markdown 592 | 593 | ### For-Each Loops 594 | 595 | We haven't covered collections yet, but you can run a for loop across all of the items in the collection (like an array) and interact with each of those items directly. The [foreach statement](https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/foreach-in) will run the contents of the loop and pass into your varaible each element in the collection, one at a time. 596 | 597 | Let's look at an example: 598 | 599 | #!csharp 600 | 601 | var arrNames = new string[] { "Fritz", "Scott", "Maria", "Jayme", "Maira", "James"}; 602 | 603 | foreach (var name in arrNames) { 604 | display(name); 605 | } 606 | 607 | #!markdown 608 | 609 | The `foreach` statement is functionally the same as the following for loop with an iterator: 610 | 611 | #!csharp 612 | 613 | for (var nameCounter = 0; nameCounter < arrNames.Length; nameCounter++) { 614 | display(arrNames[nameCounter]); 615 | } 616 | 617 | #!markdown 618 | 619 | ### While and Do Loops 620 | 621 | `while` and `do` loops have almost identical structure and perform the same task. You provide a test condition over which the contents of the loop should continue to be executed. The [while loop](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/while) executes the test FIRST before the loop statements, and the [do loop](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/do) executes the test AFTER the statements. 622 | 623 | Consider the examples of each statement below. The each start with a counter value of 6. Only the do loop executes and the while loop does not execute as the test fails immediately. 624 | 625 | #!csharp 626 | 627 | var counter = 6; 628 | 629 | while (counter < 5) { 630 | counter++; 631 | display(counter); 632 | } 633 | 634 | #!csharp 635 | 636 | var counter = 6; 637 | 638 | do { 639 | counter++; 640 | display(counter); 641 | } while (counter < 5); 642 | 643 | #!markdown 644 | 645 | ## Summary 646 | 647 | There is so much more to cover about C# and interacting with the .NET frameworks. You can learn more through our [Get Started with .NET series](https://dotnet.microsoft.com/learn) 648 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-dotnet-pack", 3 | "version": "1.0.13", 4 | "preview": true, 5 | "publisher": "ms-dotnettools", 6 | "author": "Microsoft Corporation", 7 | "displayName": ".NET Extension Pack", 8 | "description": "The ultimate collection of extensions for working with .NET in VS Code!", 9 | "license": "SEE LICENSE IN LICENSE", 10 | "icon": "dotnet-logo.png", 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/dotnet/vscode-dotnet-pack.git" 14 | }, 15 | "homepage": "https://github.com/dotnet/vscode-dotnet-pack", 16 | "bugs": { 17 | "url": "https://github.com/dotnet/vscode-dotnet-pack/issues" 18 | }, 19 | "keywords": [ 20 | "dotnet", 21 | ".NET", 22 | ".NET Core", 23 | ".NET Interactive", 24 | "dotnet Interactive", 25 | "Polyglot Notebooks", 26 | "C#", 27 | "csharp", 28 | "F#", 29 | "fsharp", 30 | "Jupyter", 31 | "notebooks", 32 | "interactive programming" 33 | ], 34 | "categories": [ 35 | "Extension Packs", 36 | "Programming Languages", 37 | "Debuggers", 38 | "Snippets", 39 | "Linters", 40 | "Notebooks" 41 | ], 42 | "engines": { 43 | "vscode": "^1.83.0" 44 | }, 45 | "extensionPack": [ 46 | "ms-dotnettools.csdevkit", 47 | "ms-dotnettools.dotnet-interactive-vscode", 48 | "ms-toolsai.jupyter", 49 | "Ionide.Ionide-fsharp" 50 | ], 51 | "main": "./out/extension", 52 | "activationEvents": [ 53 | "onUri", 54 | "onDebugInitialConfigurations", 55 | "onDebugResolve:blazorwasm", 56 | "onDebugResolve:coreclr", 57 | "onDebugResolve:clr", 58 | "onLanguage:csharp", 59 | "onLanguage:aspnetcorerazor", 60 | "onNotebook:dotnet-interactive", 61 | "onNotebook:dotnet-interactive-jupyter", 62 | "onNotebook:polyglot-notebook", 63 | "onNotebook:jupyter-notebook", 64 | "workspaceContains:project.json", 65 | "workspaceContains:*.csproj", 66 | "workspaceContains:*.sln", 67 | "workspaceContains:*.csx", 68 | "workspaceContains:*.cake", 69 | "workspaceContains:**/*.csproj", 70 | "workspaceContains:**/*.sln", 71 | "workspaceContains:**/*.csx", 72 | "workspaceContains:**/*.cake", 73 | "onWebviewPanel:dotnet.gettingStarted" 74 | ], 75 | "contributes": { 76 | "commands": [ 77 | { 78 | "command": "dotnet.gettingStarted", 79 | "title": ".NET: Getting Started" 80 | } 81 | ], 82 | "configuration": { 83 | "title": ".NET Extension Pack", 84 | "properties": { 85 | "dotnet.help.firstView": { 86 | "type": [ 87 | "string" 88 | ], 89 | "enum": [ 90 | "auto", 91 | "gettingStarted", 92 | "none" 93 | ], 94 | "enumDescriptions": [ 95 | "Automatically pick the first experience view", 96 | "Present the .NET Getting Started page", 97 | "Do not show any view" 98 | ], 99 | "default": "auto", 100 | "description": "Sets the default view which is presented during the first use.", 101 | "scope": "window" 102 | } 103 | } 104 | } 105 | }, 106 | "scripts": { 107 | "vscode:prepublish": "npm run build", 108 | "compile": "webpack --config webpack.config.js", 109 | "watch": "webpack --config webpack.config.js --watch --info-verbosity verbose", 110 | "build": "webpack --config webpack.config.js --mode=\"production\"", 111 | "lint": "eslint ./src/**/*.ts" 112 | }, 113 | "devDependencies": { 114 | "@types/node": "17.0.23", 115 | "@types/vscode": "1.53.0", 116 | "@typescript-eslint/eslint-plugin": "5.17.0", 117 | "@typescript-eslint/parser": "5.17.0", 118 | "eslint": "8.12.0", 119 | "eslint-plugin-jsdoc": "38.1.4", 120 | "ts-loader": "9.2.8", 121 | "typescript": "4.6.3", 122 | "vscode-tas-client": "0.1.31", 123 | "webpack": "5.70.0", 124 | "webpack-cli": "4.9.2" 125 | }, 126 | "dependencies": { 127 | "vscode-extension-telemetry-wrapper": "0.12.0" 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/commands/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import * as vscode from "vscode"; 5 | 6 | import { instrumentCommand, webviewCmdLinkHandler } from "../utils"; 7 | import { dotnetGettingStartedCmdHandler } from "../getting-started"; 8 | import { instrumentOperationAsVsCodeCommand } from "vscode-extension-telemetry-wrapper"; 9 | 10 | export function initialize(context: vscode.ExtensionContext) { 11 | context.subscriptions.push(vscode.commands.registerCommand("dotnet.gettingStarted", instrumentCommand(context, "dotnet.gettingStarted", dotnetGettingStartedCmdHandler))); 12 | context.subscriptions.push(instrumentOperationAsVsCodeCommand("dotnet.webview.runCommand", webviewCmdLinkHandler)); 13 | } 14 | -------------------------------------------------------------------------------- /src/exp/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import * as vscode from "vscode"; 5 | import { IExperimentationService, IExperimentationTelemetry, getExperimentationService, TargetPopulation } from "vscode-tas-client"; 6 | import { addContextProperty, sendInfo } from "vscode-extension-telemetry-wrapper"; 7 | import { getExtensionName, getExtensionVersion } from "../utils"; 8 | 9 | class ExperimentationTelemetry implements IExperimentationTelemetry { 10 | 11 | public setSharedProperty(name: string, value: string): void { 12 | addContextProperty(name, value); 13 | } 14 | 15 | public postEvent(eventName: string, props: Map): void { 16 | const payload: any = { __event_name__: eventName }; 17 | for (const [key, value] of props) { 18 | payload[key] = value; 19 | } 20 | 21 | sendInfo("", payload); 22 | } 23 | 24 | } 25 | 26 | let expService: IExperimentationService; 27 | 28 | export function getExpService() { 29 | return expService; 30 | } 31 | 32 | export function initialize(context: vscode.ExtensionContext) { 33 | expService = getExperimentationService( 34 | getExtensionName(), 35 | getExtensionVersion(), 36 | TargetPopulation.Public, 37 | new ExperimentationTelemetry(), 38 | context.globalState 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import * as vscode from "vscode"; 5 | import { dotnetsdk } from "vscode-dotnet-runtime"; 6 | import { dispose as disposeTelemetryWrapper, initialize, instrumentOperation } from "vscode-extension-telemetry-wrapper"; 7 | 8 | import { initialize as initUtils } from "./utils"; 9 | import { initialize as initCommands } from "./commands"; 10 | import { HelpViewType } from "./misc"; 11 | import { initialize as initExp } from "./exp"; 12 | import { scheduleAction } from "./utils/scheduler"; 13 | 14 | const isDotnetGettingStartedPresented = 'isDotnetGettingStartedPresented'; 15 | const dotnetSdkVersion = '8.0'; 16 | let gettingStartedShownByActivation = false; 17 | 18 | interface DotnetPackExtensionExports { 19 | getDotnetPath(version?: string): Promise; 20 | } 21 | 22 | export async function activate(context: vscode.ExtensionContext): Promise { 23 | initializeTelemetry(context); 24 | await instrumentOperation("activation", initializeExtension)(context); 25 | 26 | return { 27 | getDotnetPath 28 | } 29 | } 30 | 31 | async function getDotnetPath(version?: string) { 32 | const request: dotnetsdk.IDotnetAcquireContext = { 33 | version: version ?? dotnetSdkVersion, 34 | requestingExtensionId: 'ms-dotnettools.vscode-dotnet-pack' 35 | }; 36 | const commands = await vscode.commands.getCommands(); 37 | if (commands.includes('dotnet-sdk.acquireStatus')) { 38 | const result = await vscode.commands.executeCommand('dotnet-sdk.acquireStatus', request); 39 | return result?.dotnetPath; 40 | } else { 41 | return undefined; 42 | } 43 | } 44 | 45 | async function initializeExtension(_operationId: string, context: vscode.ExtensionContext) { 46 | await initUrlHandler(context); 47 | initUtils(context); 48 | initCommands(context); 49 | initExp(context); 50 | 51 | const config = vscode.workspace.getConfiguration("dotnet.help"); 52 | 53 | if (config.get("firstView") !== HelpViewType.None) { 54 | scheduleAction("showFirstView", true).then(() => { 55 | presentFirstView(context); 56 | }); 57 | } 58 | } 59 | 60 | async function initUrlHandler(context: vscode.ExtensionContext) { 61 | context.subscriptions.push( 62 | vscode.window.registerUriHandler({ 63 | handleUri: async (uri: vscode.Uri) => { 64 | switch (uri.path) { 65 | case '/gettingStarted': 66 | if (!gettingStartedShownByActivation) { 67 | await vscode.commands.executeCommand("dotnet.gettingStarted"); 68 | } 69 | break; 70 | } 71 | } 72 | })); 73 | } 74 | 75 | async function presentFirstView(context: vscode.ExtensionContext) { 76 | const config = vscode.workspace.getConfiguration("dotnet.help"); 77 | const firstView = config.get("firstView"); 78 | switch (firstView) { 79 | case HelpViewType.None: 80 | break; 81 | default: 82 | await showGettingStartedView(context); 83 | } 84 | } 85 | 86 | async function showGettingStartedView(context: vscode.ExtensionContext, _isForce: boolean = false) { 87 | if (!!context.globalState.get(isDotnetGettingStartedPresented)) { 88 | return; 89 | } 90 | 91 | await vscode.commands.executeCommand("dotnet.gettingStarted"); 92 | gettingStartedShownByActivation = true; 93 | context.globalState.update(isDotnetGettingStartedPresented, true); 94 | } 95 | 96 | function initializeTelemetry(_context: vscode.ExtensionContext) { 97 | const ext = vscode.extensions.getExtension("ms-dotnettools.vscode-dotnet-pack"); 98 | const packageInfo = ext ? ext.packageJSON : undefined; 99 | if (packageInfo) { 100 | if (packageInfo.aiKey) { 101 | initialize(packageInfo.id, packageInfo.version, packageInfo.aiKey, { firstParty: true }); 102 | } 103 | } 104 | } 105 | 106 | export async function deactivate() { 107 | await disposeTelemetryWrapper(); 108 | } 109 | -------------------------------------------------------------------------------- /src/getting-started/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import * as vscode from "vscode"; 5 | import * as path from "path"; 6 | 7 | export async function dotnetGettingStartedCmdHandler(context: vscode.ExtensionContext) { 8 | const editors = vscode.window.visibleTextEditors; 9 | if (editors.some(editor => editor.document.fileName.endsWith('Getting Started with .NET.dib'))) { 10 | return; 11 | } 12 | 13 | const notebookPath = context.asAbsolutePath(path.join('misc', 'Getting Started with .NET.dib')); 14 | const notebookUri = vscode.Uri.file(notebookPath); 15 | 16 | await vscode.commands.executeCommand('vscode.openWith', notebookUri, 'polyglot-notebook'); 17 | } 18 | -------------------------------------------------------------------------------- /src/misc/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import * as vscode from "vscode"; 5 | 6 | export enum HelpViewType { 7 | Auto = "auto", 8 | GettingStarted = "gettingStarted", 9 | None = "none", 10 | } 11 | 12 | function showInfoButton() { 13 | const config = vscode.workspace.getConfiguration("dotnet.help"); 14 | const firstView = config.get("firstView"); 15 | 16 | let infoButton = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right); 17 | switch (firstView) { 18 | case HelpViewType.None: 19 | return; 20 | default: 21 | infoButton.command = "dotnet.gettingStarted"; 22 | } 23 | 24 | infoButton.text = "$(info)"; 25 | infoButton.tooltip = "Learn more about .NET features"; 26 | infoButton.show(); 27 | } 28 | 29 | export function initialize(_context: vscode.ExtensionContext) { 30 | showInfoButton(); 31 | } 32 | -------------------------------------------------------------------------------- /src/utils/command.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import * as vscode from "vscode"; 5 | import { instrumentOperation } from "vscode-extension-telemetry-wrapper"; 6 | 7 | export type CommandHandler = (context: vscode.ExtensionContext, operationId: string, ...args: any[]) => any; 8 | 9 | export function instrumentCommand(context: vscode.ExtensionContext, operationName: string, callback: CommandHandler): (...args: any[]) => any { 10 | const stub = async (operationId: string, ...args: any[]) => { 11 | return await callback(context, operationId, ...args); 12 | }; 13 | 14 | return instrumentOperation(operationName, stub); 15 | } 16 | -------------------------------------------------------------------------------- /src/utils/extension.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | export function getExtensionName() { 5 | const packageInfo = getPackageInfo(); 6 | return `${packageInfo["publisher"]}.${packageInfo["name"]}`; 7 | } 8 | 9 | export function getExtensionVersion() { 10 | return getPackageInfo()["version"]; 11 | } 12 | 13 | function getPackageInfo() { 14 | return {} = require("../../package.json"); 15 | } 16 | -------------------------------------------------------------------------------- /src/utils/idle.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import * as vscode from "vscode"; 5 | 6 | // in milliseconds 7 | let timeElapsed: number = 0; 8 | const INTERVAL = 1000; 9 | // reference - https://medium.com/@slhenty/ui-response-times-acec744f3157 10 | // 5s is when users start to lose focus 11 | const IDLE_THRESHOLD = 5000; 12 | 13 | export function initialize(context: vscode.ExtensionContext) { 14 | context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(vscodeEventHandler)); // switching editor 15 | context.subscriptions.push(vscode.window.onDidChangeTextEditorSelection(vscodeEventHandler)); // change cursor position 16 | context.subscriptions.push(vscode.window.onDidChangeTextEditorVisibleRanges(vscodeEventHandler)); // scrolling 17 | 18 | setInterval(timerEventHandler, INTERVAL); 19 | } 20 | 21 | function vscodeEventHandler() { 22 | timeElapsed = 0; 23 | } 24 | 25 | function timerEventHandler() { 26 | timeElapsed += INTERVAL; 27 | if (timeElapsed >= IDLE_THRESHOLD) { 28 | timeElapsed = 0; 29 | _onIdle.fire(); 30 | } 31 | } 32 | 33 | const _onIdle: vscode.EventEmitter = new vscode.EventEmitter; 34 | export const onIdle: vscode.Event = _onIdle.event; 35 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import * as vscode from "vscode"; 5 | import { readFile as fsReadFile } from "fs"; 6 | import * as util from "util"; 7 | import { initialize as initializeIdle } from "./idle"; 8 | import { initialize as initializeScheduler } from "./scheduler"; 9 | import { sendInfo } from "vscode-extension-telemetry-wrapper"; 10 | 11 | const readFile = util.promisify(fsReadFile); 12 | 13 | let extensionContext: vscode.ExtensionContext; 14 | 15 | export function initialize(context: vscode.ExtensionContext) { 16 | extensionContext = context; 17 | initializeIdle(context); 18 | initializeScheduler(context); 19 | } 20 | 21 | export function getExtensionContext() { 22 | return extensionContext; 23 | } 24 | 25 | export async function loadTextFromFile(resourceUri: string) { 26 | let buffer = await readFile(resourceUri); 27 | return buffer.toString(); 28 | } 29 | 30 | export * from "./command"; 31 | export * from "./extension"; 32 | 33 | export async function webviewCmdLinkHandler(obj: { webview: string, identifier: string, command: string, args?: string[] }) { 34 | const { webview, identifier, command, args } = obj; 35 | sendInfo("", { 36 | name: "openWebviewUrl", 37 | webview, 38 | identifier 39 | }); 40 | await vscode.commands.executeCommand(command, args); 41 | } 42 | -------------------------------------------------------------------------------- /src/utils/scheduler.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. 3 | 4 | import * as vscode from "vscode"; 5 | import { onIdle } from "./idle"; 6 | 7 | interface Action { 8 | name: string; 9 | resolve: (name: string) => void; 10 | } 11 | 12 | const actionQueue: Action[] = []; 13 | const pastActions: string[] = []; 14 | 15 | export function initialize(context: vscode.ExtensionContext) { 16 | context.subscriptions.push(onIdle(() => idleHandler())); 17 | } 18 | 19 | // This is to queue the actions that need attention from users. One thing at a time, only on idle. 20 | export function scheduleAction(name: string, isImmediate: boolean = false, isOneTime: boolean = false): Promise { 21 | const isPastAction = actionQueue.some(action => action.name === name) || pastActions.includes(name); 22 | if (isOneTime && isPastAction) { 23 | return Promise.reject(`Action (${name}) was already scheduled or performed once.`); 24 | } 25 | 26 | return new Promise((resolve, _reject) => { 27 | if (isImmediate) { 28 | setImmediate(() => resolve(name)); 29 | return; 30 | } 31 | 32 | actionQueue.push({ 33 | name: name, 34 | resolve: resolve 35 | }); 36 | }); 37 | } 38 | 39 | function idleHandler() { 40 | if (actionQueue.length === 0) { 41 | return; 42 | } 43 | 44 | const action = actionQueue.shift(); 45 | pastActions.push(action && action.name || ""); 46 | 47 | if (action) { 48 | action.resolve(action && action.name); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "*": [ 6 | "types/*" 7 | ] 8 | }, 9 | "module": "commonjs", 10 | "target": "es6", 11 | "outDir": "out", 12 | "lib": [ 13 | "ES2015", 14 | "ES2016.Array.Include", 15 | "ES2017.String", 16 | "ES2018.Promise", 17 | "DOM", 18 | "DOM.Iterable", 19 | "WebWorker.ImportScripts" 20 | ], 21 | "sourceMap": true, 22 | "rootDir": "src", 23 | /* Strict Type-Checking Option */ 24 | "strict": true, /* enable all strict type-checking options */ 25 | /* Additional Checks */ 26 | "noUnusedLocals": true, /* Report errors on unused locals. */ 27 | "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 28 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 29 | "noUnusedParameters": true, /* Report errors on unused parameters. */ 30 | "allowUnreachableCode": false, /* Report errors on unreachable code. */ 31 | "skipLibCheck": true, 32 | "esModuleInterop": true, 33 | "allowSyntheticDefaultImports": true, 34 | "noImplicitThis": false /* disabled for jQuery */ 35 | }, 36 | "exclude": [ 37 | "node_modules", 38 | ".vscode-test", 39 | "**/assets", 40 | ] 41 | } -------------------------------------------------------------------------------- /types/vscode-dotnet-runtime.d.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | 3 | declare module dotnetsdk { 4 | export enum AcquireErrorConfiguration { 5 | DisplayAllErrorPopups = 0, 6 | DisableErrorPopups = 1, 7 | } 8 | 9 | export interface IDotnetAcquireContext { 10 | version: string; 11 | requestingExtensionId?: string; 12 | errorConfiguration?: AcquireErrorConfiguration; 13 | } 14 | 15 | export interface IDotnetAcquireResult { 16 | dotnetPath: string; 17 | } 18 | } 19 | 20 | declare module "vscode" { 21 | export namespace commands { 22 | export function executeCommand(command: 'dotnet-sdk.acquire', context: dotnetsdk.IDotnetAcquireContext): Thenable; 23 | export function executeCommand(command: 'dotnet-sdk.acquireStatus', context: dotnetsdk.IDotnetAcquireContext): Thenable; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = function (env, argv) { 4 | env = env || {}; 5 | 6 | return [{ 7 | name: 'extension', 8 | target: 'node', 9 | mode: 'none', 10 | entry: { 11 | extension: './src/extension.ts' 12 | }, 13 | module: { 14 | rules: [{ 15 | test: /\.ts$/, 16 | exclude: /node_modules/, 17 | use: 'ts-loader' 18 | }] 19 | }, 20 | resolve: { 21 | modules: ['node_modules', path.resolve(__dirname, 'src')], 22 | mainFiles: ['index'], 23 | extensions: ['.js', '.ts', '.json'] 24 | }, 25 | output: { 26 | filename: '[name].js', 27 | path: path.resolve(__dirname, 'out'), 28 | libraryTarget: "commonjs2", 29 | publicPath: '/', 30 | devtoolModuleFilenameTemplate: "../[resource-path]" 31 | }, 32 | externals: { 33 | 'applicationinsights-native-metrics': 'commonjs applicationinsights-native-metrics', // ignored because we don't ship native module 34 | 'diagnostic-channel-publishers': 'commonjs diagnostic-channel-publishers', 35 | vscode: 'commonjs vscode' 36 | }, 37 | devtool: 'source-map' 38 | }] 39 | }; 40 | --------------------------------------------------------------------------------