Skip to main content

Projects and when to add one

Runesmith is split into C# projects so that each part has one job, carries only the dependencies that job needs, and can be built and tested on its own. A project is not free, though: it adds a build step, a test project, a place to look for code and a seam that has to stay stable. This page says when a new project is worth that cost.

The checklist​

Add a project under src/ only when every item holds. If one does not, put the code in the existing project it belongs to.

  • One responsibility you can name in a few words, such as "the text buffer" or "the language server client", and no existing project already has it.
  • A clean place in the dependency graph. It depends only on projects below it, nothing below it would need to depend on it, and the split creates no cycle.
  • A dependency reason. It carries a dependency that other projects must not carry, such as Avalonia, VS-MEF or TextMateSharp, or other projects must be able to use it without carrying its dependencies.
  • A small public surface. Callers use it through a handful of public types, and its internals can change without touching them.
  • It works on its own. It can be built, tested and benchmarked without the shell, for example headless or without a window.
  • Real code today. It holds several types of code that exists now or is part of the current plan, not a single class and not code that might come one day.
  • Not a dumping ground. It is not a Common, Utilities or Helpers project. Shared code goes into the lowest project that needs it.
  • Its costs are paid. It gets a test project in tests/, a row on this page and on the architecture page.

These are signs that code should stay where it is:

  • It has one caller.
  • It always changes together with another project.
  • Splitting it out would need many internal members to become public.

The official plugins, such as C# and Java support, are not projects in this repository. Each lives in its own repository in the RunesmithHub organization, builds against the published packages, and reaches Runesmith through the plugin hub like a third-party plugin, which proves that pipeline works. See Bundled plugins.

The projects​

ProjectResponsibilityWhy it is its own project
Runesmith.TextThe text buffer: a piece table with immutable snapshots, line lookup, edits, undo history and text searchEvery other part uses it; it has no dependencies at all, so it can be tested and benchmarked in isolation.
Runesmith.LspA Language Server Protocol client: JSON-RPC over streams, the protocol types and a server's lifecycleIt knows nothing about Runesmith, so it stays reusable and testable against any server; only System.Text.Json.
Runesmith.SdkThe plugin API: plugin lifecycle, the service contracts plugins use and the extension points they exportPlugins reference only this project. It must stay small and stable, and must not carry the shell, VS-MEF or TextMate.
Runesmith.CompositionFinding, validating and loading plugins, and composing them with VS-MEF, including the composition cacheThe only project that depends on VS-MEF. It runs headless, so plugin loading can be tested without a window.
Runesmith.HubThe plugin hub client: the verified index, search, install plans, installs, updates and the hub's states for installed pluginsIt decides what plugins run, so it is built into the host, and it runs headless: the app uses it before any window exists, and its tests run against a signed sample index. The only project besides the composition that uses RunesmithHub.Protocol.
Runesmith.WorkspaceFolders, solutions, the file tree and watcher, the file index for quick open, documents on disk and find in filesPure file system and text work with no UI dependency, testable headless.
Runesmith.LanguageServicesThe core of the language analyzers: documents and their versions, request lanes, completion ranking and metricsShared by the editor and runesmith-language-server, so it depends on neither; only Runesmith.Text.
Runesmith.LanguagesThe language registry, TextMate highlighting, and the bridges that turn language servers and in-process analyzers into editor featuresThe only project that carries TextMateSharp and that uses Runesmith.Lsp.
Runesmith.Languages.CSharpThe C# analyzer, on the C# compilerIt carries the compiler, which only the C# plugin and the language server should load.
Runesmith.Languages.Java.SyntaxA lexer and parser for Java 8 to 25No dependencies, so it can be tested against the JDK's sources and benchmarked on its own.
Runesmith.Languages.JavaThe Java analyzer: class files, the JDK's API per release, projects and the semantic modelOnly the Java plugin loads it.
Runesmith.LanguageServerrunesmith-language-server, the analyzers served over the Language Server ProtocolAn executable for other tools; the editor itself runs the analyzers in its own process.
Runesmith.EditorThe text editor control: layout, rendering, input, completion, hover, diagnostics and the find barThe largest UI component. It depends on the SDK contracts only, not on TextMate or language servers, so it can be developed and tested on its own.
Runesmith.ShellThe IDE window: docking, commands, menus, the command palette, settings, the status bar and the tool windowsIt wires everything together; nothing depends on it except the application.
Runesmith.AppThe executable: the command line, the single running instance and the desktop platformKeeps the desktop backend out of the shell, so the shell can run headless.
tools/Runesmith.BundledPluginsFetches, checks and unpacks the bundled plugins during the app's buildA build tool, run by src/Runesmith.App; nothing ships it.

Each project has a matching project in tests/. benchmarks/Runesmith.Benchmarks holds the benchmarks, and benchmarks/Runesmith.TypingBenchmark the typing benchmark.