{"id":18602980,"url":"https://github.com/devlooped/smallsharp","last_synced_at":"2026-01-12T06:49:48.667Z","repository":{"id":40296080,"uuid":"300154250","full_name":"devlooped/SmallSharp","owner":"devlooped","description":"Create, edit and run multiple C# top-level programs  in the same project by just selecting the startup program from the start  button.","archived":false,"fork":false,"pushed_at":"2025-04-12T00:26:01.000Z","size":7051,"stargazers_count":294,"open_issues_count":1,"forks_count":13,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-12T01:27:11.542Z","etag":null,"topics":["console-application","csharp","csharp-sourcegenerator","learning","visual-studio"],"latest_commit_sha":null,"homepage":"https://clarius.org/SmallSharp","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devlooped.png","metadata":{"files":{"readme":"readme.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"devlooped"}},"created_at":"2020-10-01T05:19:49.000Z","updated_at":"2025-04-02T04:56:32.000Z","dependencies_parsed_at":"2024-01-06T09:54:46.974Z","dependency_job_id":"5f188877-d707-424c-a1d6-195dd69d5840","html_url":"https://github.com/devlooped/SmallSharp","commit_stats":{"total_commits":135,"total_committers":6,"mean_commits":22.5,"dds":0.3925925925925926,"last_synced_commit":"dac83180423bdc7536f9936f881cd1994640256d"},"previous_names":["kzu/smallsharp"],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devlooped%2FSmallSharp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devlooped%2FSmallSharp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devlooped%2FSmallSharp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devlooped%2FSmallSharp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devlooped","download_url":"https://codeload.github.com/devlooped/SmallSharp/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248586243,"owners_count":21128995,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["console-application","csharp","csharp-sourcegenerator","learning","visual-studio"],"created_at":"2024-11-07T02:13:09.137Z","updated_at":"2026-01-12T06:49:48.661Z","avatar_url":"https://github.com/devlooped.png","language":"C#","readme":"![Icon](https://raw.githubusercontent.com/devlooped/SmallSharp/main/assets/img/icon-32.png) SmallSharp\n============\n\n[![Version](https://img.shields.io/nuget/v/SmallSharp.svg?color=royalblue)](https://www.nuget.org/packages/SmallSharp) \n[![Downloads](https://img.shields.io/nuget/dt/SmallSharp?color=darkmagenta)](https://www.nuget.org/packages/SmallSharp) \n[![EULA](https://img.shields.io/badge/EULA-OSMF-blue?labelColor=black\u0026color=C9FF30)](https://github.com/devlooped/SmallSharp/blob/main/osmfeula.txt)\n[![OSS](https://img.shields.io/github/license/devlooped/SmallSharp.svg?color=blue)](https://github.com/devlooped/SmallSharp/blob/main/license.txt) \n\n\u003c!-- #description --\u003e\nCreate, edit and run multiple C# file-based apps in the same project in the IDE, honoring per-file `#:package` \nreferences, `#:property` project values and even `#:sdk` 😍\n\u003c!-- #description --\u003e\n\n\u003c!-- include https://github.com/devlooped/.github/raw/main/osmf.md --\u003e\n## Open Source Maintenance Fee\n\nTo ensure the long-term sustainability of this project, users of this package who generate \nrevenue must pay an [Open Source Maintenance Fee](https://opensourcemaintenancefee.org). \nWhile the source code is freely available under the terms of the [License](license.txt), \nthis package and other aspects of the project require [adherence to the Maintenance Fee](osmfeula.txt).\n\nTo pay the Maintenance Fee, [become a Sponsor](https://github.com/sponsors/devlooped) at the proper \nOSMF tier. A single fee covers all of [Devlooped packages](https://www.nuget.org/profiles/Devlooped).\n\n\u003c!-- https://github.com/devlooped/.github/raw/main/osmf.md --\u003e\n\n\u003c!-- #content --\u003e\n## Overview\n\nC# [top-level programs](https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/top-level-statements) \nallow a very intuitive, simple and streamlined experience for quickly spiking or learning C#. \nThe addition of [file-based apps](https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-app/) in \n.NET 10 [takes this further](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives#file-based-apps) by allowing package references and even MSBuild properties to be \nspecified per file:\n\n```csharp\n#:package Humanizer@2.14.1\n#:property ImplicitUsings=true\n#:property Nullable=enable\n\nusing Humanizer;\n\nvar dotNet9Released = DateTimeOffset.Parse(\"2024-12-03\");\nvar since = DateTimeOffset.Now - dotNet9Released;\n\nConsole.WriteLine($\"It has been {since.Humanize()} since .NET 9 was released.\");\n```\n\nEditing these standalone files in VSCode, however, is suboptimal compared with the full C# \nexperience in Visual Studio. In Visual Studio, though, you can only have one top-level program \nin a project, and as of now, you cannot leverage the `#:package` and `#:property` directives \nat all.\n\n**SmallSharp** allows dynamically selecting the file to run, right from the Start button/dropdown \n(for compilation and launch/debug). It also automatically restores the `#:package` references so \nthe project system can resolve them, and even emits the `#:property` directives if present to customize \nthe build as needed.\n\n![start button](https://raw.githubusercontent.com/devlooped/SmallSharp/main/assets/img/launchSettings.png)\n\nThis list is automatically kept in sync as you add more `.cs` files to the project. When you select \none target C# file, that becomes the only top-level program to be compiled, so you don't have to \nmodify any of the others since they automatically become *None* items. \n\n\u003e [!TIP]\n\u003e An initial build after selection change migh be needed to restore the packages and compile the \n\u003e selected file, unless you're using the SDK mode for SmallSharp (see below).\n\nAll compile files directly under the project directory root are considered top-level programs for \nselection and compilation purposes. If you need to share code among them, you can place additional \nfiles in subdirectories and those will behave like normal compile items.\n\n## Usage\n\nSmallSharp works by just installing the \n[SmallSharp](https://nuget.org/packages/SmallSharp) nuget package in a C# console project \nand adding a couple extra properties to the project file:\n\n```xml\n\u003cProject Sdk=\"Microsoft.NET.Sdk\"\u003e\n\n  \u003cPropertyGroup\u003e\n    \u003cOutputType\u003eExe\u003c/OutputType\u003e\n    \u003c!-- 👇 allows c# file to override the TF via a #:property --\u003e\n    \u003cTargetFramework Condition=\"$(TargetFramework) == ''\"\u003enet10.0\u003c/TargetFramework\u003e\n\n    \u003c!-- 👇 additional properties required in package mode --\u003e\n    \u003cImportProjectExtensionProps\u003etrue\u003c/ImportProjectExtensionProps\u003e\n    \u003cImportProjectExtensionTargets\u003etrue\u003c/ImportProjectExtensionTargets\u003e   \n  \u003c/PropertyGroup\u003e\n\n  \u003cItemGroup\u003e\n    \u003cPackageReference Include=\"SmallSharp\" Version=\"*\" PrivateAssets=\"all\" /\u003e\n  \u003c/ItemGroup\u003e\n\n\u003c/Project\u003e\n```\n\nThere are some limitations with this mode, however: \n* You cannot use the `#:sdk` [directive](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/preprocessor-directives#file-based-apps) \n  to specify a different SDK per file, since the project file already specifies one.\n* CLI-based builds may require multiple passes to restore and build the selected file, since \n  the package is only restored after the first build.\n* You must add ImportProjectExtensionProps/ImportProjectExtensionTargets manually, polluting the \n  project file.\n\nSo the recommended way to use SmallSharp is via the SDK mode, which results in a more streamlined \nand seamless experience across IDE and CLI builds:\n\n```xml\n\u003cProject Sdk=\"SmallSharp/2.2.3\"\u003e\n\n  \u003cPropertyGroup\u003e\n    \u003cOutputType\u003eExe\u003c/OutputType\u003e\n    \u003c!-- 👇 allows c# file to override the TF via a #:property --\u003e\n    \u003cTargetFramework Condition=\"$(TargetFramework) == ''\"\u003enet10.0\u003c/TargetFramework\u003e\n  \u003c/PropertyGroup\u003e\n\n\u003c/Project\u003e\n```\n\nThe SDK mode will always produce a successful build in a single `dotnet build` pass even if you \nchange the `ActiveFile` between builds.\n\n\u003e [!IMPORTANT]\n\u003e If no `#:sdk` directive is provided by a specific C# file-based app, the `Microsoft.NET.SDK` will be \n\u003e used by default in this SDK mode.\n\nKeep adding as many top-level programs as you need, and switch between them easily by simply \nselecting the desired file from the Start button dropdown.\n\nWhen running from the command-line, you can select the file to run by passing it as an argument to `dotnet run`:\n\n```bash\ndotnet run -p:start=program1.cs\n```\n\nYou can also use the shortcut `-p:s=[FILE]`.\n\n## How It Works\n\nThis nuget package leverages in concert the following standalone and otherwise \nunrelated features of the compiler, nuget and MSBuild:\n\n1. The C# compiler only allows one top-level program per compilation.\n2. Launch profiles (the entries in the Run dropdown) are populated from the Properties\\launchSettings.json file\n3. Whenever changed, the dropdown selection is persisted as the `$(ActiveDebugProfile)` MSBuild property in a file \n   named after the project with the `.user` extension\n4. This file is imported before NuGet-provided MSBuild targets\n5. VS ignores `#:` directives when adding the flag `FileBasedProgram` to the `$(Features)` project property.\n\nUsing the above features in concert, **SmallSharp** essentially does the following:\n\n* Emit top-level files as a `launchSettings.json` profile and set the `$(ActiveDebugProfile)`.\n\n* Exclude `.cs` files at the project level from being included as `\u003cCompile\u003e` by the default SDK \n  includes and include them explicitly as `\u003cNone\u003e` instead so they show up in the solution explorer. \n  This prevents the compiler from causing an error for multiple top-level programs.\n\n* Explicitly include as `\u003cCompile\u003e` only the `$(ActiveDebugProfile)` property value.\n\n* Emit `#:package` and `#:property` directive to an automatically imported `obj\\SmallSharp.targets` file\n\n* SmallSharp MSBuild SDK automatically imports the `SmallSharp.targets` file, which causes a new \n  restore to automatically happen in Visual Studio, bringing all required dependencies automatically.\n\nThis basically mean that this it will also work consistently if you use `dotnet run` from the command-line, \nsince the \"Main\" file selection is performed exclusively via MSBuild item manipulation.\n\n\u003e [!TIP]\n\u003e It is recommended to keep the project file to its bare minimum, usually having just the SmallSharp \n\u003e SDK reference, and do all project/package references in the top-level files using the `#:package` and \n\u003e `#:property` directives for improved isolation between the different file-based apps.\n\n![run humanizer file](https://raw.githubusercontent.com/devlooped/SmallSharp/main/assets/img/runfile1.png)\n\n![run mcp file](https://raw.githubusercontent.com/devlooped/SmallSharp/main/assets/img/runfile2.png)\n\u003c!-- #content --\u003e\n\n\u003c!-- include https://github.com/devlooped/sponsors/raw/main/footer.md --\u003e\n# Sponsors \n\n\u003c!-- sponsors.md --\u003e\n[![Clarius Org](https://avatars.githubusercontent.com/u/71888636?v=4\u0026s=39 \"Clarius Org\")](https://github.com/clarius)\n[![MFB Technologies, Inc.](https://avatars.githubusercontent.com/u/87181630?v=4\u0026s=39 \"MFB Technologies, Inc.\")](https://github.com/MFB-Technologies-Inc)\n[![SandRock](https://avatars.githubusercontent.com/u/321868?u=99e50a714276c43ae820632f1da88cb71632ec97\u0026v=4\u0026s=39 \"SandRock\")](https://github.com/sandrock)\n[![DRIVE.NET, Inc.](https://avatars.githubusercontent.com/u/15047123?v=4\u0026s=39 \"DRIVE.NET, Inc.\")](https://github.com/drivenet)\n[![Keith Pickford](https://avatars.githubusercontent.com/u/16598898?u=64416b80caf7092a885f60bb31612270bffc9598\u0026v=4\u0026s=39 \"Keith Pickford\")](https://github.com/Keflon)\n[![Thomas Bolon](https://avatars.githubusercontent.com/u/127185?u=7f50babfc888675e37feb80851a4e9708f573386\u0026v=4\u0026s=39 \"Thomas Bolon\")](https://github.com/tbolon)\n[![Kori Francis](https://avatars.githubusercontent.com/u/67574?u=3991fb983e1c399edf39aebc00a9f9cd425703bd\u0026v=4\u0026s=39 \"Kori Francis\")](https://github.com/kfrancis)\n[![Uno Platform](https://avatars.githubusercontent.com/u/52228309?v=4\u0026s=39 \"Uno Platform\")](https://github.com/unoplatform)\n[![Reuben Swartz](https://avatars.githubusercontent.com/u/724704?u=2076fe336f9f6ad678009f1595cbea434b0c5a41\u0026v=4\u0026s=39 \"Reuben Swartz\")](https://github.com/rbnswartz)\n[![Jacob Foshee](https://avatars.githubusercontent.com/u/480334?v=4\u0026s=39 \"Jacob Foshee\")](https://github.com/jfoshee)\n[![](https://avatars.githubusercontent.com/u/33566379?u=bf62e2b46435a267fa246a64537870fd2449410f\u0026v=4\u0026s=39 \"\")](https://github.com/Mrxx99)\n[![Eric Johnson](https://avatars.githubusercontent.com/u/26369281?u=41b560c2bc493149b32d384b960e0948c78767ab\u0026v=4\u0026s=39 \"Eric Johnson\")](https://github.com/eajhnsn1)\n[![David JENNI](https://avatars.githubusercontent.com/u/3200210?v=4\u0026s=39 \"David JENNI\")](https://github.com/davidjenni)\n[![Jonathan ](https://avatars.githubusercontent.com/u/5510103?u=98dcfbef3f32de629d30f1f418a095bf09e14891\u0026v=4\u0026s=39 \"Jonathan \")](https://github.com/Jonathan-Hickey)\n[![Charley Wu](https://avatars.githubusercontent.com/u/574719?u=ea7c743490c83e8e4b36af76000f2c71f75d636e\u0026v=4\u0026s=39 \"Charley Wu\")](https://github.com/akunzai)\n[![Ken Bonny](https://avatars.githubusercontent.com/u/6417376?u=569af445b6f387917029ffb5129e9cf9f6f68421\u0026v=4\u0026s=39 \"Ken Bonny\")](https://github.com/KenBonny)\n[![Simon Cropp](https://avatars.githubusercontent.com/u/122666?v=4\u0026s=39 \"Simon Cropp\")](https://github.com/SimonCropp)\n[![agileworks-eu](https://avatars.githubusercontent.com/u/5989304?v=4\u0026s=39 \"agileworks-eu\")](https://github.com/agileworks-eu)\n[![Zheyu Shen](https://avatars.githubusercontent.com/u/4067473?v=4\u0026s=39 \"Zheyu Shen\")](https://github.com/arsdragonfly)\n[![Vezel](https://avatars.githubusercontent.com/u/87844133?v=4\u0026s=39 \"Vezel\")](https://github.com/vezel-dev)\n[![ChilliCream](https://avatars.githubusercontent.com/u/16239022?v=4\u0026s=39 \"ChilliCream\")](https://github.com/ChilliCream)\n[![4OTC](https://avatars.githubusercontent.com/u/68428092?v=4\u0026s=39 \"4OTC\")](https://github.com/4OTC)\n[![Vincent Limo](https://avatars.githubusercontent.com/devlooped-user?s=39 \"Vincent Limo\")](https://github.com/v-limo)\n[![domischell](https://avatars.githubusercontent.com/u/66068846?u=0a5c5e2e7d90f15ea657bc660f175605935c5bea\u0026v=4\u0026s=39 \"domischell\")](https://github.com/DominicSchell)\n[![Justin Wendlandt](https://avatars.githubusercontent.com/u/1068431?u=f7715ed6a8bf926d96ec286f0f1c65f94bf86928\u0026v=4\u0026s=39 \"Justin Wendlandt\")](https://github.com/jwendl)\n[![Adrian Alonso](https://avatars.githubusercontent.com/u/2027083?u=129cf516d99f5cb2fd0f4a0787a069f3446b7522\u0026v=4\u0026s=39 \"Adrian Alonso\")](https://github.com/adalon)\n[![Michael Hagedorn](https://avatars.githubusercontent.com/u/61711586?u=8f653dfcb641e8c18cc5f78692ebc6bb3a0c92be\u0026v=4\u0026s=39 \"Michael Hagedorn\")](https://github.com/Eule02)\n[![torutek](https://avatars.githubusercontent.com/u/33917059?v=4\u0026s=39 \"torutek\")](https://github.com/torutek)\n[![mccaffers](https://avatars.githubusercontent.com/u/16667079?u=739e110e62a75870c981640447efa5eb2cb3bc8f\u0026v=4\u0026s=39 \"mccaffers\")](https://github.com/mccaffers)\n[![Christoph Hochstätter](https://avatars.githubusercontent.com/u/17645550?u=01bbdcb84d03cac26260f1c951e046d24a324591\u0026v=4\u0026s=39 \"Christoph Hochstätter\")](https://github.com/christoh)\n[![ADS Fund](https://avatars.githubusercontent.com/u/202042116?v=4\u0026s=39 \"ADS Fund\")](https://github.com/ADS-Fund)\n\n\n\u003c!-- sponsors.md --\u003e\n[![Sponsor this project](https://avatars.githubusercontent.com/devlooped-sponsor?s=118 \"Sponsor this project\")](https://github.com/sponsors/devlooped)\n\n[Learn more about GitHub Sponsors](https://github.com/sponsors)\n\n\u003c!-- https://github.com/devlooped/sponsors/raw/main/footer.md --\u003e\n","funding_links":["https://github.com/sponsors/devlooped","https://github.com/sponsors"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevlooped%2Fsmallsharp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevlooped%2Fsmallsharp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevlooped%2Fsmallsharp/lists"}