diff --git a/README.md b/README.md index f7b8518..ba7d9fb 100644 --- a/README.md +++ b/README.md @@ -182,7 +182,7 @@ Console.WriteLine(document.Target); // Session ``` You write C# and tmux receives tmux: `Session.Name` goes on the wire as -`session_name`, and `Client.IsControlClient` as `client_control`. The catalog +`session_name`, and `Client.IsControlClient` as `client_control_mode`. The catalog carries that pair for all twelve queryable fields, and it is closed — a field outside it throws `UnsupportedQueryExpressionException` rather than falling back, so an expression that translates is one tmux can answer. diff --git a/src/LibTmux.Generators/FieldCatalogGenerator.cs b/src/LibTmux.Generators/FieldCatalogGenerator.cs index 1c14625..02ad8ec 100644 --- a/src/LibTmux.Generators/FieldCatalogGenerator.cs +++ b/src/LibTmux.Generators/FieldCatalogGenerator.cs @@ -16,13 +16,13 @@ public sealed class FieldCatalogGenerator : IIncrementalGenerator /// The closed catalog, and where each field lives on its entity. /// /// Wire name and property are declared explicitly because the mapping is - /// not systematic (client_controlIsControlClient, and two + /// not systematic (client_control_modeIsControlClient, and two /// fields have no property at all). /// private static readonly (string WireName, string Target, bool Relation, string? Property)[] Fields = { - ("client_control", "Client", false, "IsControlClient"), + ("client_control_mode", "Client", false, "IsControlClient"), ("client_id", "Client", false, null), ("client_name", "Client", false, "Name"), ("pane_command", "Pane", false, null), diff --git a/src/LibTmux.Query.Json/README.md b/src/LibTmux.Query.Json/README.md index 293e413..8266786 100644 --- a/src/LibTmux.Query.Json/README.md +++ b/src/LibTmux.Query.Json/README.md @@ -82,7 +82,7 @@ Console.WriteLine($"depth {QueryJsonLimits.V1.MaximumDepth}, nodes {QueryJsonLim `session_name`, `session_attached`, `session_id`, `session_windows`, `window_name`, `window_id`, `window_panes`, `pane_id`, `pane_command`, -`client_id`, `client_name`, `client_control`. +`client_id`, `client_name`, `client_control_mode`. You write these as the properties they are — `Session.Name`, `Client.IsControlClient` — and the wire carries the tmux spelling. diff --git a/src/LibTmux.Query.Json/libtmux-query-v1.schema.json b/src/LibTmux.Query.Json/libtmux-query-v1.schema.json index adf694e..98a4dbc 100644 --- a/src/LibTmux.Query.Json/libtmux-query-v1.schema.json +++ b/src/LibTmux.Query.Json/libtmux-query-v1.schema.json @@ -50,7 +50,7 @@ "target": { "$ref": "#/$defs/target" }, "wireName": { "enum": [ - "client_control", + "client_control_mode", "client_id", "client_name", "pane_command", @@ -99,7 +99,7 @@ "properties": { "target": { "const": "client" }, "wireName": { - "enum": ["client_control", "client_id", "client_name"] + "enum": ["client_control_mode", "client_id", "client_name"] } } } @@ -112,7 +112,7 @@ { "$ref": "#/$defs/field" }, { "properties": { - "wireName": { "enum": ["client_control", "session_attached"] } + "wireName": { "enum": ["client_control_mode", "session_attached"] } } } ] diff --git a/src/LibTmux/Client.Administration.cs b/src/LibTmux/Client.Administration.cs index 58b669e..4589295 100644 --- a/src/LibTmux/Client.Administration.cs +++ b/src/LibTmux/Client.Administration.cs @@ -41,7 +41,7 @@ internal Client( public string? Tty => ReadSnapshot("client_tty"); /// Gets whether the client speaks tmux's control protocol. - public bool IsControlClient => ReadSnapshot("client_control") == "1"; + public bool IsControlClient => ReadSnapshot("client_control_mode") == "1"; /// Gets the session the client was attached to when it was read. /// diff --git a/src/LibTmux/Query/QueryTranslator.cs b/src/LibTmux/Query/QueryTranslator.cs index 7e16a1a..26cc4d2 100644 --- a/src/LibTmux/Query/QueryTranslator.cs +++ b/src/LibTmux/Query/QueryTranslator.cs @@ -213,7 +213,7 @@ private static QueryNode TranslateOperand( private static FieldNode FieldFor(MemberInfo member) { // What tmux calls a field is not a transformation of what C# calls - // it -- Client.IsControlClient is client_control, not + // it -- Client.IsControlClient is client_control_mode, not // is_control_client. The catalog carries that pairing; an unknown // type is a caller's own row, whose property names are wire names already. string wireName = diff --git a/src/LibTmux/README.md b/src/LibTmux/README.md index a732a7e..009741b 100644 --- a/src/LibTmux/README.md +++ b/src/LibTmux/README.md @@ -213,7 +213,7 @@ QueryDocument document = QueryExtensions.Translate( You write C# and tmux receives tmux. The catalog carries the pair for all twelve queryable fields — `Session.Name` is `session_name`, -`Client.IsControlClient` is `client_control` — and it is closed: +`Client.IsControlClient` is `client_control_mode` — and it is closed: | Session | Window | Pane | Client | |---|---|---|---| diff --git a/tests/LibTmux.IntegrationTests/Clients/ClientAdministrationTests.cs b/tests/LibTmux.IntegrationTests/Clients/ClientAdministrationTests.cs index 9327d0c..0095080 100644 --- a/tests/LibTmux.IntegrationTests/Clients/ClientAdministrationTests.cs +++ b/tests/LibTmux.IntegrationTests/Clients/ClientAdministrationTests.cs @@ -72,6 +72,29 @@ await Assert.ThrowsAsync( } } + [Fact( + Skip = "Requires a Unix process environment.", + SkipType = typeof(UnixTestEnvironment), + SkipUnless = nameof(UnixTestEnvironment.IsUnix))] + public async Task Control_client_reads_back_as_one() + { + await using RawTmuxTestContext raw = await RawTmuxTestContext.StartAsync( + TestContext.Current.CancellationToken); + CancellationToken token = TestContext.Current.CancellationToken; + Server server = await ConnectAsync(raw, token); + + await using ControlModeClientScope control = await ControlModeClientScope.StartAsync( + raw, + token); + + // The only assertion in the suite a broken read cannot satisfy: every + // other client test attaches a terminal, for which false is the right + // answer whether or not the field resolves. + Client client = await WaitForClientAsync(server, token); + Assert.Equal(control.ClientName, client.Name); + Assert.True(client.IsControlClient); + } + [Fact( Skip = "Requires a Unix process environment.", SkipType = typeof(UnixTestEnvironment), diff --git a/tests/LibTmux.UnitTests/Query/QuerySemanticsTests.cs b/tests/LibTmux.UnitTests/Query/QuerySemanticsTests.cs index 669c896..306cbf5 100644 --- a/tests/LibTmux.UnitTests/Query/QuerySemanticsTests.cs +++ b/tests/LibTmux.UnitTests/Query/QuerySemanticsTests.cs @@ -24,7 +24,7 @@ public void An_entity_translates_through_the_name_tmux_uses_for_the_field() // The one that a naming rule would never produce. Assert.Equal( - "client_control", + "client_control_mode", Field(QueryExtensions.Translate(client => client.IsControlClient))); }