IEnumerable <Range> SelectSplit(Range range, SelectSplitDialog.Result result) { var stack = new Stack <SelectSplitEnum>(); stack.Push(SelectSplitEnum.None); var charValue = new Dictionary <char, SelectSplitEnum> { ['('] = SelectSplitEnum.Parentheses, [')'] = SelectSplitEnum.Parentheses, ['['] = SelectSplitEnum.Brackets, [']'] = SelectSplitEnum.Brackets, ['{'] = SelectSplitEnum.Braces, ['}'] = SelectSplitEnum.Braces, ['<'] = SelectSplitEnum.LTGT, ['>'] = SelectSplitEnum.LTGT, }; var start = range.Start; var pos = start; var matchPos = -1; var matchLen = 0; while (true) { var stackTop = stack.Peek(); if (stackTop.HasFlag(SelectSplitEnum.String)) { if (pos >= range.End) { throw new Exception("Incomplete string"); } else if ((pos + 1 < range.End) && (Data.Data[pos] == '\\') && (!stackTop.HasFlag(SelectSplitEnum.VerbatimString))) { pos += 2; } else if ((pos + 1 < range.End) && (Data.Data[pos] == '"') && (Data.Data[pos + 1] == '"') && (stackTop.HasFlag(SelectSplitEnum.VerbatimString))) { pos += 2; } else if ((pos + 1 < range.End) && (Data.Data[pos] == '{') && (Data.Data[pos + 1] == '{') && (stackTop.HasFlag(SelectSplitEnum.InterpolatedString))) { pos += 2; } else if ((Data.Data[pos] == '{') && (stackTop.HasFlag(SelectSplitEnum.InterpolatedString))) { stack.Push(SelectSplitEnum.Braces); ++pos; } else if (Data.Data[pos] == '"') { stack.Pop(); ++pos; } else { ++pos; } } else { if ((stackTop == SelectSplitEnum.None) && (pos > matchPos)) { var match = result.Regex.Match(GetString(new Range(pos, range.End))); if (match.Success) { if (match.Length == 0) { throw new Exception("Cannot split on empty selection"); } matchPos = match.Index + pos; matchLen = match.Length; } else { matchPos = range.End; matchLen = 0; } } if ((pos >= range.End) || ((pos == matchPos) && (stackTop == SelectSplitEnum.None))) { if (stack.Count != 1) { throw new Exception($"Didn't find close for {stackTop}"); } var useStart = start; var useEnd = pos; if (result.TrimWhitespace) { while ((useStart < pos) && (char.IsWhiteSpace(Data.Data[useStart]))) { ++useStart; } while ((useEnd > useStart) && (char.IsWhiteSpace(Data.Data[useEnd - 1]))) { --useEnd; } } if ((result.IncludeEmpty) || (useStart != useEnd)) { yield return(new Range(useEnd, useStart)); } if (pos >= range.End) { break; } if (result.IncludeResults) { yield return(Range.FromIndex(pos, matchLen)); } pos += matchLen; start = pos; } else if (((result.BalanceParens) && (Data.Data[pos] == '(')) || ((result.BalanceBrackets) && (Data.Data[pos] == '[')) || ((result.BalanceBraces) && (Data.Data[pos] == '{')) || ((result.BalanceLTGT) && (Data.Data[pos] == '<'))) { stack.Push(charValue[Data.Data[pos++]]); } else if (((result.BalanceParens) && (Data.Data[pos] == ')')) || ((result.BalanceBrackets) && (Data.Data[pos] == ']')) || ((result.BalanceBraces) && (Data.Data[pos] == '}')) || ((result.BalanceLTGT) && (Data.Data[pos] == '>'))) { if (charValue[Data.Data[pos]] != stackTop) { throw new Exception($"Didn't find open for {Data.Data[pos]}"); } stack.Pop(); ++pos; } else if ((result.BalanceStrings) && (Data.Data[pos] == '\"')) { stack.Push(SelectSplitEnum.String); ++pos; } else if ((result.BalanceStrings) && (pos + 1 < range.End) && (Data.Data[pos] == '@') && (Data.Data[pos + 1] == '\"')) { stack.Push(SelectSplitEnum.VerbatimString); pos += 2; } else if ((result.BalanceStrings) && (pos + 1 < range.End) && (Data.Data[pos] == '$') && (Data.Data[pos + 1] == '\"')) { stack.Push(SelectSplitEnum.InterpolatedString); pos += 2; } else if ((result.BalanceStrings) && (pos + 2 < range.End) && (Data.Data[pos] == '$') && (Data.Data[pos + 1] == '@') && (Data.Data[pos + 2] == '\"')) { stack.Push(SelectSplitEnum.InterpolatedVerbatimString); pos += 3; } else { ++pos; } } } }
void Command_Select_Split(SelectSplitDialog.Result result) { var indexes = GetFixedExpressionResults <int>(result.Index); SetSelections(Selections.AsParallel().AsOrdered().SelectMany((range, index) => SelectSplit(range, result).Skip(indexes[index] == 0 ? 0 : indexes[index] - 1).Take(indexes[index] == 0 ? int.MaxValue : 1)).ToList()); }