public async Task ExecuteAsync(AsyncData data, WorkSession session, ICommandResultSender sender, CancellationToken cancellationToken) { var first = data.GetFirst(); var endOffset = first.Offset + first.Count - 1; var partStart = first.Offset; int? start = null; int? length = null; int? cursorPosition = null; string?reason = null; for (var i = first.Offset; i <= endOffset; i++) { if (first.Array[i] != (byte)':') { continue; } var part = new ArraySegment <byte>(first.Array, partStart, i - partStart); if (start == null) { start = FastConvert.Utf8ByteArrayToInt32(part); partStart = i + 1; continue; } if (length == null) { length = FastConvert.Utf8ByteArrayToInt32(part); partStart = i + 1; continue; } if (cursorPosition == null) { cursorPosition = FastConvert.Utf8ByteArrayToInt32(part); partStart = i + 1; continue; } reason = part.Count > 0 ? Encoding.UTF8.GetString(part) : string.Empty; partStart = i + 1; break; } if (start == null || length == null || cursorPosition == null || reason == null) { throw new FormatException("Command arguments must be 'start:length:cursor:reason:text'."); } var text = await AsyncDataConvert.ToUtf8StringAsync(data, partStart - first.Offset, _charArrayPool).ConfigureAwait(false); session.ReplaceText(text, start.Value, length.Value); session.CursorPosition = cursorPosition.Value; await _signatureHelp.ApplyCursorPositionChangeAsync(session, sender, cancellationToken).ConfigureAwait(false); await _completion.ApplyReplacedTextAsync(reason, _typedCharEffects, session, sender, cancellationToken).ConfigureAwait(false); }
public async Task ExecuteAsync(AsyncData data, WorkSession session, ICommandResultSender sender, CancellationToken cancellationToken) { // this doesn't happen too often, so microptimizations are not required var optionsString = await AsyncDataConvert.ToUtf8StringAsync(data, 0, _charArrayPool).ConfigureAwait(false); var options = optionsString .Split(Comma) .Select(p => p.Split(EqualsSign)) .ToDictionary(p => p[0], p => p[1]); if (options.TryGetValue(LanguageOptionName, out var language)) { // this has to be done first, as it might reset other options SetLanguage(session, language); session.RawOptionsFromClient[LanguageOptionName] = language; } foreach (var option in options) { var(name, value) = (option.Key, option.Value); if (name == LanguageOptionName) { continue; } if (name.StartsWith("x-")) { if (!(_extension?.TrySetOption(session, name, value) ?? false)) { throw new FormatException($"Extension option '{name}' was not recognized."); } session.RawOptionsFromClient[name] = value; continue; } throw new FormatException($"Option '{name}' was not recognized (to use {nameof(ISetOptionsFromClientExtension)}, make sure your option name starts with 'x-')."); } await SendOptionsEchoAsync(session, sender, cancellationToken).ConfigureAwait(false); }