public static List <GotoRange> GetPositionsData(IEnumerable <string> strs, GotoType gotoType) { void setFile(GotoRange pd, string value) => pd.File = value; void setStartLine(GotoRange pd, string value) => pd.Start.Line = int.Parse(value) - 1; void setEndLine(GotoRange pd, string value) => pd.End.Line = int.Parse(value) - 1; void setStartIndex(GotoRange pd, string value) => pd.Start.Index = int.Parse(value) - 1; void setEndIndex(GotoRange pd, string value) => pd.End.Index = int.Parse(value) - 1; void setStartColumn(GotoRange pd, string value) => pd.Start.Column = int.Parse(value) - 1; void setEndColumn(GotoRange pd, string value) => pd.End.Column = int.Parse(value) - 1; void setStartPosition(GotoRange pd, string value) => pd.Start.Position = int.Parse(value); void setEndPosition(GotoRange pd, string value) => pd.End.Position = int.Parse(value); string regexPattern; List <Action <GotoRange, string> > actions; switch (gotoType) { case GotoType.Line: regexPattern = @"^(?:((?:[a-z]:)?[\w\s,\\.-]+):)?(\d+)(?:-(\d+))?|((?:[a-z]:)?[\w\s,\\.-]+)\((\d+)\)$"; actions = new List <Action <GotoRange, string> > { setFile, setStartLine, setEndLine, setFile, setStartLine }; break; case GotoType.Column: regexPattern = @"^(?:(?:((?:[a-z]:)?[\w\s,\\.-]+):)?(\d+):)?(\d+)(?:-(?:(\d+):)?(\d+))?$"; actions = new List <Action <GotoRange, string> > { setFile, setStartLine, setStartColumn, setEndLine, setEndColumn }; break; case GotoType.Index: regexPattern = @"^(?:(?:((?:[a-z]:)?[\w\s,\\.-]+):)?(\d+):)?(\d+)(?:-(?:(\d+):)?(\d+))?|((?:[a-z]:)?[\w\s,\\.-]+)\((\d+),(\d+),(\d+),(\d+)\)$"; actions = new List <Action <GotoRange, string> > { setFile, setStartLine, setStartIndex, setEndLine, setEndIndex, setFile, setStartLine, setStartIndex, setEndLine, setEndIndex }; break; case GotoType.Position: regexPattern = @"^(?:((?:[a-z]:)?[\w\s,\\.-]+):)?(\d+)(?:-(\d+))?$"; actions = new List <Action <GotoRange, string> > { setFile, setStartPosition, setEndPosition }; break; default: throw new Exception("Invalid gototype"); } var regex = new Regex(regexPattern, RegexOptions.IgnoreCase); var result = new List <GotoRange>(); foreach (var str in strs) { var pd = new GotoRange(); var match = regex.Match(str); if (!match.Success) { throw new Exception($"Invalid location: {str} ({gotoType})"); } for (var ctr = 0; ctr < actions.Count; ++ctr) { if (match.Groups[ctr + 1].Success) { actions[ctr](pd, match.Groups[ctr + 1].Value); } } result.Add(pd); } return(result); }
void Command_Position_Goto(GotoType gotoType, bool selecting, PositionGotoDialog.Result result) { var values = GotoRange.GetPositionsData(GetVariableExpressionResults <string>(result.Expression), gotoType); if (!values.Any()) { return; } var hasFiles = values.First().File != null; if (values.Any(x => (x.File != null) != hasFiles)) { throw new Exception("Either all locations must have files or none"); } var valuesByFile = new List <List <GotoRange> >(); var fileMap = new Dictionary <string, List <GotoRange> >(StringComparer.OrdinalIgnoreCase); foreach (var value in values) { List <GotoRange> list; if (result.OpenFilesOnce) { var key = value.File ?? ""; if (!fileMap.ContainsKey(key)) { fileMap[key] = list = new List <GotoRange>(); valuesByFile.Add(list); } else { list = fileMap[key]; } } else { list = new List <GotoRange>(); valuesByFile.Add(list); } list.Add(value); } if (hasFiles) { var invalidFiles = valuesByFile.Select(list => list.First().File).NonNull().Where(file => !File.Exists(file)).ToList(); if (invalidFiles.Any()) { throw new Exception($"The following files could not be found: {string.Join("\n", invalidFiles)}"); } } var active = new HashSet <TextEditor>(); foreach (var list in valuesByFile) { var useTE = list.First().File == null ? this : TabsParent.Add(list.First().File); active.Add(useTE); var sels = useTE.Selections.ToList(); var positions = list; if ((sels.Count == 0) && ((gotoType == GotoType.Line) || (gotoType == GotoType.Position))) { sels.Add(useTE.BeginRange); } if (sels.Count == 1) { sels = sels.Resize(positions.Count, sels[0]).ToList(); } if (positions.Count == 1) { positions = positions.Expand(sels.Count, positions[0]).ToList(); } if (positions.Count != sels.Count) { throw new Exception("Expression count doesn't match selection count"); } useTE.SetSelections(sels.AsParallel().AsOrdered().Select((range, ctr) => positions[ctr].GetRange(useTE, range, selecting)).ToList()); } if (hasFiles) { foreach (var item in TabsParent.Items) { item.Active = active.Contains(item); } TabsParent.TopMost = active.First(); } }