-
-
Notifications
You must be signed in to change notification settings - Fork 60
Code Conventions
Sucrose enforces a tight, consistent code style across its many projects, and one convention in particular — the namespace-alias acronym rule — is so pervasive that code which ignores it will look wrong immediately. This page documents that aliasing rule, the directory conventions inside shared projects, the .editorconfig style rules (which are build errors, not suggestions, because EnforceCodeStyleInBuild=true), and the project-wide language settings. Follow these exactly when contributing.
- Namespace alias convention (critical)
- Directory conventions
- Style rules (.editorconfig)
- Project-wide language settings
- The settings pattern
- Example file header
- See also
Every Sucrose (and Skylark) namespace import is aliased to a short uppercase acronym formed from the first letter of each namespace segment. Never use fully-qualified names, and never use a bare using for a Sucrose namespace. Real examples:
using SHC = Skylark.Helper.Culture; // S-H-C
using SMMCG = Sucrose.Memory.Manage.Constant.General; // S-M-M-C-G
using SMMI = Sucrose.Manager.Manage.Internal; // S-M-M-I
using SMMRG = Sucrose.Memory.Manage.Readonly.General; // S-M-M-R-G
using SSDECT = Sucrose.Shared.Dependency.Enum.CompatibilityType;
using SSSHP = Sucrose.Shared.Space.Helper.Processor;
using SPVPLP = Sucrose.Portal.Views.Pages.LibraryPage;Rules:
- The alias is the first letter of each namespace segment, uppercased.
-
Collisions are disambiguated by appending more letters from the final segment. For example,
SSDECTis used forSucrose.Shared.Dependency.Enum.CompatibilityType, distinguishing it fromSucrose.Shared.Dependency.Enum.CommandType(which would otherwise also acronym toSSDEC). -
usingdirectives go outside the namespace.
When you write new code, derive aliases the same way and reuse the existing alias for a namespace if the file already imports it elsewhere in the codebase.
Files inside shared projects are organized by role (see Shared Item Projects for the full list of projects):
| Folder | Contents |
|---|---|
Enum/ |
Enum types |
Helper/ |
Static helper/utility classes |
Manage/ |
Configuration/state management |
Manage/Manager/ |
Settings-manager classes |
Manage/Readonly/ |
Read-only constants |
Struct/ |
Struct types |
Extension/ |
Extension methods |
Services/ |
Pipe/signal service classes (in .Pipe, .Signal) |
Event/, View/
|
Used in engine shared projects (XAML views and event handlers) |
EnforceCodeStyleInBuild=true is set in Directory.Build.props, so .editorconfig violations fail the build locally. The key rules:
| Rule | Setting |
|---|---|
| Indentation |
4 spaces (indent_style = space, tab_width = 4) |
| Line endings |
CRLF (end_of_line = crlf) |
| XML files | indent 2 spaces ([*.xml] indent_size = 2) |
| Namespaces |
block-scoped (csharp_style_namespace_declarations = block_scoped) |
| Type/method/property/event naming | PascalCase |
| Field naming | camelCase |
| Interfaces |
prefixed I (dotnet_naming_style.begins_with_i.required_prefix = I) |
using placement |
outside the namespace (csharp_using_directive_placement = outside_namespace) |
| Types |
explicit types, not var (csharp_style_var_* = false) |
| Expression-bodied members | Yes for accessors/properties/indexers/lambdas; No for methods/constructors/operators/local functions |
| Operator wrapping | operator_placement_when_wrapping = beginning_of_line |
| Preferred patterns | pattern matching, switch expressions, null propagation/coalescing, compound assignment, simplified interpolation |
| Suggested (not enforced) | primary constructors, readonly structs, UTF-8 string literals (all :suggestion) |
Two notes about .editorconfig:
- It contains a full duplicate
[*.vb]naming block (Turkish-named rules). VB is not used in the app — it is legacy/IDE-generated and can be ignored. - Because CI only compiles 7 Library projects (see Building From Source), CI will not catch a style violation in an engine, the Portal, or a shared project — but your local build will, since enforcement is on.
From Directory.Build.props:
-
Nullableis disabled project-wide. ImplicitUsingsis enabled.-
LangVersionispreview(C# preview language features are available). -
Optimize=falseis set globally (even for Release). -
CS8632,WFO0003,SYSLIB0014are suppressed.
Settings are the most common thing contributors add, and they follow a strict pattern. Settings live in the Sucrose.Manager class library (src/Library/Sucrose.Manager/Manage/*.cs), grouped by area: General, System, Personal (Private), Library, Portal, Engine, Backgroundog, Aurora, Cycling, Donate, Hook, Update, Warehouse, Internal. Each setting is a static property that reads/writes through a SettingManager with a constant key and an inline default:
public static string Culture => SMMI.GeneralSettingManager.GetSetting(SMMCG.Culture, SHC.CurrentUITwoLetterISOLanguageName);
public static int RunStartup => SHS.Clamp(SMMI.GeneralSettingManager.GetSettingStable(SMMCG.RunStartup, 0), 0, 10);
public static bool TelemetryData => SMMI.GeneralSettingManager.GetSetting(SMMCG.TelemetryData, true);- Setting keys are constants in
Sucrose.Memory.Manage.Constant.*(aliasedSMMCG, etc.). - The manager instance comes from
Sucrose.Manager.Manage.Internal(SMMI). - Use
GetSettingStableplusSHS.Clampfor bounded integers. - Defaults are passed inline to
GetSetting/GetSettingStable.
See the full recipe for adding a setting in Extending Sucrose, and how the JSON is persisted in Settings Persistence.
A representative file header obeying the aliasing rule and using-outside-namespace convention:
using SHC = Skylark.Helper.Culture;
using SMMCG = Sucrose.Memory.Manage.Constant.General;
using SMMI = Sucrose.Manager.Manage.Internal;
namespace Sucrose.Manager.Manage
{
public static class General
{
public static string Culture => SMMI.GeneralSettingManager.GetSetting(SMMCG.Culture, SHC.CurrentUITwoLetterISOLanguageName);
}
}Getting Started
- Installation
- System Requirements
- Quick Start
- Portal Interface Tour
- Updating Sucrose
- Uninstalling Sucrose
Wallpaper Types
Using Sucrose
- Managing Library
- Using Store
- Customizing Wallpaper
- Multi-Monitor
- Wallpaper Cycling
- Choosing Engines
- Performance Rules
- Theme, Tray & Startup
- Discord Rich Presence
Settings Reference
- Settings Overview
- Settings: General
- Settings: Personal
- Settings: Performance
- Settings: Wallpaper
- Settings: System
- Settings: Other
- Settings: All Keys
Creating Wallpapers
- Create Overview
- Create: Step By Step
- Create: Package Format
- Create: Customization Controls
- Create: JS Bridge
- Create: Audio API
- Create: System API
- Create: Property Listener & Filters
- Create: Web Architecture
- Create: Compatibility
- Create: Example Wallpapers
- Create: Sharing & Publishing
Engine Reference
- Engines Overview
- Engine: MpvPlayer
- Engine: VlcPlayer
- Engine: WebView
- Engine: CefSharp
- Engine: Nebula
- Engine: Vexana
- Engine: Xavier
- Engine: Aurora
- Engine Comparison
Automation & Command Line
Architecture & Internals
- Architecture Overview
- Lifecycle
- Commandog Dispatcher
- Single-Instance Mutexes
- IPC
- Backgroundog Service
- Crash Reporting
- Update Internals
- Property Service
- Undo Internals
Data, Files & Diagnostics
Building & Contributing
- Building From Source
- Repository Layout
- Shared Item Projects
- Code Conventions
- Preprocessor Symbols
- Publish Pipeline
- Bundle Installer Internals
- Extending Sucrose
- Contributing
- Translating with Localizer
- Localization Coverage
- Security Policy
- Privacy & Telemetry
Help & Support