private string?GetSelectedTextFromFile(DocumentUri uri, Range?range)
        {
            if (range is null)
            {
                return(null);
            }

            var contents   = File.ReadAllText(uri.GetFileSystemPath());
            var lineStarts = TextCoordinateConverter.GetLineStarts(contents);
            var start      = TextCoordinateConverter.GetOffset(lineStarts, range.Start.Line, range.Start.Character);
            var end        = TextCoordinateConverter.GetOffset(lineStarts, range.End.Line, range.End.Character);

            var selectedText = contents.Substring(start, end - start);

            return(selectedText);
        }
Пример #2
0
        // If the insertion path already exists, or can't be added (eg array instead of object exists on the path), returns null
        public (int line, int column, string insertText)? InsertIfNotExist(string[] propertyPaths, object valueIfNotExist)
        {
            if (propertyPaths.Length == 0)
            {
                throw new ArgumentException($"{nameof(propertyPaths)} must not be empty");
            }

            if (string.IsNullOrWhiteSpace(_json))
            {
                return(AppendToEndOfJson(Stringify(PropertyPathToObject(propertyPaths, valueIfNotExist))));
            }

            TextReader textReader = new StringReader(_json);
            JsonReader jsonReader = new JsonTextReader(textReader);

            JObject?jObject = null;

            try
            {
                jObject = JObject.Load(jsonReader, new JsonLoadSettings
                {
                    LineInfoHandling = LineInfoHandling.Load,
                    CommentHandling  = CommentHandling.Load,
                    DuplicatePropertyNameHandling = DuplicatePropertyNameHandling.Ignore,
                });
            }
            catch (Exception)
            {
            }

            if (jObject is null)
            {
                // Just append to existing text
                return(AppendToEndOfJson(Stringify(PropertyPathToObject(propertyPaths, valueIfNotExist))));
            }

            JObject?      currentObject  = jObject;
            List <string> remainingPaths = new(propertyPaths);

            while (remainingPaths.Count > 0)
            {
                string path      = PopFromLeft(remainingPaths);
                JToken?nextLevel = currentObject[path];
                if (nextLevel is null)
                {
                    int    line           = ((IJsonLineInfo)currentObject).LineNumber - 1; // 1-indexed to 0-indexed
                    int    column         = ((IJsonLineInfo)currentObject).LinePosition - 1;
                    object insertionValue = valueIfNotExist;
                    remainingPaths.Reverse();
                    foreach (string propertyName in remainingPaths)
                    {
                        Dictionary <string, object> newObject = new();
                        newObject[propertyName] = insertionValue;
                        insertionValue          = newObject;
                    }
                    remainingPaths.Reverse();
                    string newPath = string.Join('.', remainingPaths);
                    string insertionValueAsString = Stringify(insertionValue);

                    int  insertLine;
                    int  insertColumn;
                    int  currentIndent;
                    bool hasSiblings = currentObject.Children().Any(child => child.Type != JTokenType.Comment);
                    insertLine    = line;
                    insertColumn  = column + 1;
                    currentIndent = GetIndentationOfLine(line) + _indent; // use indent of line with the starting "{" as the nested indent level

                    // We will insert before the first sibling
                    string propertyInsertion =
                        "\n" +
                        IndentEachLine(
                            $"\"{path}\": {insertionValueAsString}",
                            currentIndent);
                    if (hasSiblings)
                    {
                        propertyInsertion += ",";
                    }

                    // Need a newline after the insertion if there's anything else on the line
                    var  lineStarts         = TextCoordinateConverter.GetLineStarts(_json);
                    int  offset             = TextCoordinateConverter.GetOffset(lineStarts, line, column);
                    char?charAfterInsertion = _json.Length > offset ? _json[offset + 1] : null;
                    if (charAfterInsertion != '\n' && charAfterInsertion != '\r')
                    {
                        propertyInsertion += '\n';
                    }

                    return(insertLine, insertColumn, propertyInsertion);
                }

                if (remainingPaths.Count == 0)
                {
                    // We found matches all the way to the leaf, doesn't matter what the leaf value is, we will leave it alone
                    return(null);
                }

                if (nextLevel is JObject nextObject)
                {
                    currentObject = nextObject;
                }
                else
                {
                    return(null);
                }
            }

            return(null);
        }