Hi All,
I added `ob-csharp.el' (and friends) to the org-mode repository in this
commit:
https://cgit.git.savannah.gnu.org/cgit/emacs/org-mode.git/commit/?id=526a7d1cc65409d5546b009f54fed28726a9457d
The mailing list discussion for this can be found here:
https://list.orgmode.org/baf0e7b4-8233-4669-94bb-89dbde3c07be@edison/
The attached patch aims to put the documentation in synch with these
additions.
Please let me know if there is something missing or similar.
Thanks and best regards,
Maximilian Kueffner
From 84b2ddeecc5dd1d5001a35f7378306c777bd87f6 Mon Sep 17 00:00:00 2001
From: Maximilian Kueffner <poverobuosodon...@gmail.com>
Date: Sun, 17 Aug 2025 12:30:42 +0200
Subject: [PATCH] Add ob-doc-csharp.org
---
org-contrib/babel/languages/ob-doc-csharp.org | 251 ++++++++++++++++++
1 file changed, 251 insertions(+)
create mode 100644 org-contrib/babel/languages/ob-doc-csharp.org
diff --git a/org-contrib/babel/languages/ob-doc-csharp.org
b/org-contrib/babel/languages/ob-doc-csharp.org
new file mode 100644
index 00000000..42304277
--- /dev/null
+++ b/org-contrib/babel/languages/ob-doc-csharp.org
@@ -0,0 +1,251 @@
+#+OPTIONS: H:3 num:nil toc:2 \n:nil ::t |:t ^:{} -:t f:t *:t tex:t
d:(HIDE) tags:not-in-toc
+#+STARTUP: align fold nodlcheck hidestars oddeven lognotestate hideblocks
+#+TITLE: org-babel Support for C# source blocks
+#+AUTHOR: Maximilian Kueffner
+#+EMAIL: poverobuosodon...@gmail.com
+#+LANGUAGE: en
+#+HTML_LINK_UP: index.html
+#+HTML_LINK_HOME: https://orgmode.org/worg/
+#+EXCLUDE_TAGS: noexport
+
+#+name: banner
+#+begin_export html
+ <div id="subtitle" style="float: center; text-align: center;">
+ <p>
+ Org Mode support for
+ <br><a href="https://dotnet.microsoft.com/en-us/languages/csharp">C#</a>
+ </p>
+ <p>
+ <a href="https://dotnet.microsoft.com/en-us/languages/csharp"><img
src="https://upload.wikimedia.org/wikipedia/commons/f/ff/C-Sharp_Logo.svg"/></a>
+ </p>
+ </div>
+#+end_export
+
+* Introduction
+
+Babel can compile and evaluate C# code blocks with this module. It is
different from
[[https://git.sr.ht/~bzg/org-contrib/tree/master/item/lisp/ob-csharp.el][ob-csharp
in org-contrib]] in that it allows for significantly more complex setups,
which is outlined in the following.
+A C# code-block
++ will be compiled in the context of a
[[https://learn.microsoft.com/en-us/aspnet/web-forms/overview/deployment/web-deployment-in-the-enterprise/understanding-the-project-file][csproj-file]]
++ it can have dependencies on
+ - other projects (define in csproj-files)
+ - compiled assemblies (*.dll-files)
+ - [[https://www.nuget.org/][nuget]] packages (custom nuget feeds can be
configured)
++ can be compiled with arbitrary
[[https://dotnet.microsoft.com/en-us/download][.NET SDKs]]
++ allows for arbitrary project settings
+
+* Requirements and Setup
+
+A version of [[https://dotnet.microsoft.com/en-us/download][.NET]] should be
installed on the host system that is executing the C# code blocks.
+Please make sure that the target framework configured in the variable
~org-babel-csharp-default-target-framework~ is available on your system.
Currently, this variable is set to the most recent discoverable .NET SDK found
on the host system.
+If that is not what you intend as a default, this variable can be configured
e.g. like
+#+begin_src elisp
+ (setf org-babel-csharp-default-target-framework "net8.0")
+#+end_src
+
+* Org Mode Features for C#
+
+** Configuration
+
+There are a few global variable that will have effect on *every* C# code block.
+
+- =org-babel-csharp-compiler= :: sets the compiler that will be used to
compile the code block's csproj file. Default is ~dotnet~.
+
+- =org-babel-csharp-default-target-framework= :: depending on the installed
.NET SDKs (get a list by calling ~dotnet --list-sdks~), this variable can be
set as desired. It will be used as the default when no ~:framework~ header
argument was given. If not configured, the most recent discoverable version
will be used.
+
+- =org-babel-csharp-additional-project-flags= :: if the default "minimal
viable" csproj configuration does not fit your needs, you can add arbitrary
additional configuration here. When not ~nil~ it will be put in the main
~PropertyGroup~ section of the csproj file. Note that it must be in "encoded"
in a valid XML syntax as it will be used as-is. You can for example set the
build configuration of the code-block to /Release/ with ~(setq
org-babel-csharp-additional-project-flags
"<Configuration>Release</Configuration>")~
+
+
+You might want to reset some of these variables to their defaults in case you
need different, or default, configuration in subsequent code blocks.
+
+** Header arguments
+
+- =:main= :: defines whether or not to wrap the code block's content in a
default ~void Main(string[] args)~ function. Anything other than ~"no"~
(including no =:main= argument at all) as a value for this argument will result
in wrapping the code block in a ~Main~ function when expanding.
+
+- =:nugetconfig= :: path to a custom /NuGet.config/ file to use for the code
block. This is useful if you have a local *.nupkg or a feed different from
[[nuget.org]] and want to use it in your source block.
+
+- =:framework= :: the
[[https://learn.microsoft.com/en-us/dotnet/standard/frameworks][target
framework]] of the code block. See ~org-babel-csharp-default-target-framework~
for permanent configuration of this.
+
+- =:class= :: defines the name of the program wrapper class. It accepts string
arguments. If left empty, it will use the default name ~Program~ as a program
wrapper class name. A value of ~"no"~ will inhibit a wrapper class.
+
+- =:references= :: accepts a list of dependencies. Three types of references
are allowed
+ 1. *Project References* can be passed using a full or relative path to an
existing project. To set a project reference, the file path will need a
~.csproj~ file extension. Example: =:references '(
"/home/me/otherproject/theproject.csproj")=
+ 2. *Assembly Reference* can be passed using a full or relative path to an
existing assembly. To set an assembly reference, the file path will need a
~.dll~ file extension. Example: =:references '(
"/home/me/otherproject/theproject.dll")=
+ 3. *Nuget Package Reference* can be passed by simply adding the correct name
of the package to the reference list. In order for this to work, the
=org-babel-csharp-nuget-config= should define a nuget feed from where this
package can be fetched. To set a nuget reference, don't add a file extension to
the dependency. In case you want a package with a specific version, pass the
respective package as a cons cell where the cdr is a string representing the
desired version. Example: =:references '(Newtonsoft.Json)= will give you /any/
version of [[https://www.newtonsoft.com/json][Newtonsoft.Json]], =:references
'(("Newtonsoft.Json" . "13.0.3"))= will give you version /13.0.3/ of that
package.
+
+- =:usings= :: a list of namespaces to include in the using block of the
resulting .cs file. This is
+ + a convenience feature when you set ~:class "no" :main "no"~ (as you could
type ~using project.a.featureb;~ at the start of the code block)
+ + a necessity if the main function and the wrapper class are generated
automatically and you need to pass in namespace dependencies (and don't want to
write fully qualified names for usages of the respective external dependencies)
+
+- =:cmdline= :: command line arguments that will be passed to the compiled
executable of the respective source block.
+
+* Examples
+
+** Minimal Viable C# Code Block
+
+Simply adding a new code block and setting its language to =csharp= is
sufficient.
+The following will compile and evaluate (as an ~<OutputType>Exe</OutputType>~
project).
+#+begin_example
+#+begin_src csharp
+ Console.WriteLine("Hello from C#");
+#+end_src
+#+end_example
+
+#+begin_src csharp :exports results
+ Console.WriteLine("Hello from C#");
+#+end_src
+
+#+RESULTS:
+: Hello from C#
+
+** Custom Class
+
+By default, the code within the code block is wrapped in a class called
~Program~. This name can be configured in with the =:class= header argument.
Whether or not an automated ~Main~ function should be created can be configured
in the =:main= header argument (everything else than "no" will result in an
automatic main function).
+The generated code will be put in a temporary directory governed by
~org-babel-temporary-directory~.
+
+The following code block will be
++ wrapped in a class ~MyTest~
++ completely wrapped in a ~static void Main(string[] args)~ function
+
+#+begin_example
+#+begin_src csharp :class "MyClass" :usings '("System" "System.Diagnostics"
"System.Reflection") :main yes
+ string projectName = Assembly.GetCallingAssembly().GetName().Name;
+ string projectDirectory = "my-test";
+ var stackTrace = new StackTrace();
+ var firstStackFrame = stackTrace.GetFrame(0);
+ string methodName = firstStackFrame.GetMethod().ToString();
+ string className = firstStackFrame.GetMethod().DeclaringType.ToString();
+
+ Console.WriteLine($"Directory:\t{projectDirectory}");
+ Console.WriteLine($"Project:\t{projectName}");
+ Console.WriteLine($"Class:\t{className}");
+ Console.WriteLine($"Method:\t{methodName}");
+#+end_src
+#+end_example
+
+#+begin_src csharp :class "MyClass" :usings '("System" "System.Diagnostics"
"System.Reflection") :main yes :exports results
+ string projectName = Assembly.GetCallingAssembly().GetName().Name;
+ string dllName = Path.GetFileName(Assembly.GetEntryAssembly().Location);
+ var stackTrace = new StackTrace();
+ var firstStackFrame = stackTrace.GetFrame(0);
+ string methodName = firstStackFrame.GetMethod().ToString();
+ string className = firstStackFrame.GetMethod().DeclaringType.ToString();
+
+ Console.WriteLine($"Dll Name:\t{dllName}");
+ Console.WriteLine($"Project:\t{projectName}");
+ Console.WriteLine($"Class:\t{className}");
+ Console.WriteLine($"Method:\t{methodName}");
+#+end_src
+
+#+RESULTS:
+| Dll Name: | obcsRELp52.dll |
+| Project: | obcsRELp52 |
+| Class: | obcsi7SYVW.MyClass |
+| Method: | Void Main(System.String[]) |
+
+** Input Variables
+
+Idiomatic variable types are detected automatically. The following code block
indicates the correct detection of
++ ~System.Int32~
++ ~System.Double~
++ ~System.String~
+
+#+begin_example
+#+begin_src csharp :var a=3 b="pizza" c=5.3 d=-1
+ int myInt = 1;
+ string PrintTypeVal<T>(T tp)
+ {
+ return $"{tp.GetType().ToString()} {tp}";
+ }
+
+ var myString =
$"{PrintTypeVal(myInt)}\n{PrintTypeVal(a)}\n{PrintTypeVal(b)}\n{PrintTypeVal(c)}\n{PrintTypeVal(d)}";
+
+ Console.WriteLine(myString);
+#+end_src
+#+end_example
+
+#+begin_src csharp :var a=3 b="pizza" c=5.3 d=-1 :exports results
+ int myInt = 1;
+ string PrintTypeVal<T>(T tp)
+ {
+ return $"{tp.GetType().ToString()} {tp}";
+ }
+
+ var myString =
$"{PrintTypeVal(myInt)}\n{PrintTypeVal(a)}\n{PrintTypeVal(b)}\n{PrintTypeVal(c)}\n{PrintTypeVal(d)}";
+
+ Console.WriteLine(myString);
+#+end_src
+
+#+RESULTS:
+| System.Int32 | 1 |
+| System.Int32 | 3 |
+| System.String | pizza |
+| System.Double | 5.3 |
+| System.Int32 | -1 |
+
+** Output Formatting
+
+In the above code blocks, tabular output was used implicitly. List output is
supported as well but must be specified like so
+
+#+begin_example
+#+begin_src csharp :results raw list
+ Console.WriteLine("Item 1");
+ Console.WriteLine("Item 2");
+ Console.WriteLine("Item 3");
+ Console.WriteLine("Item 4");
+#+end_src
+#+end_example
+
+#+begin_src csharp :results raw list :exports results
+ Console.WriteLine("Item 1");
+ Console.WriteLine("Item 2");
+ Console.WriteLine("Item 3");
+ Console.WriteLine("Item 4");
+#+end_src
+
+#+RESULTS:
+- Item 1
+- Item 2
+- Item 3
+- Item 4
+
+** NuGet References
+
+With the following code block, we create a string serialization based on the
[[https://www.newtonsoft.com/json][Newtonsoft.Json]] NuGet package. Since this
is available from [[https://www.nuget.org/][nuget.org]], no additional
configuration is needed.
+#+begin_example
+#+begin_src csharp :references '(("Newtonsoft.Json" . "13.0.3")) :usings
'("System" "Newtonsoft.Json") :main no :project "json-test" :results raw
+ public class DTO
+ {
+ public int TheInt { get; set; }
+ public string TheString { get; set; }
+ }
+
+ static void Main(string[] args)
+ {
+ DTO myDto = new() { TheInt = 12, TheString = "ok" };
+
+ string json = JsonConvert.SerializeObject(myDto, Formatting.Indented);
+ Console.WriteLine($"{json}");
+ }
+#+end_src
+#+end_example
+#+begin_src csharp :references '(("Newtonsoft.Json" . "13.0.3")) :usings
'("System" "Newtonsoft.Json") :main no :project "json-test" :results raw
:exports results
+ public class DTO
+ {
+ public int TheInt { get; set; }
+ public string TheString { get; set; }
+ }
+
+ static void Main(string[] args)
+ {
+ DTO myDto = new() { TheInt = 12, TheString = "ok" };
+
+ string json = JsonConvert.SerializeObject(myDto, Formatting.Indented);
+ Console.WriteLine($"{json}");
+ }
+#+end_src
+
+#+RESULTS:
+{
+ "TheInt": 12,
+ "TheString": "ok"
+}
--
2.49.0