//===--- Format.cpp -----------------------------------------*- C++-*------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "Format.h" #include "support/Logger.h" #include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" #include "clang/Lex/Lexer.h" #include "clang/Tooling/Core/Replacement.h" #include "llvm/Support/Unicode.h" namespace clang { namespace clangd { namespace { /// Append closing brackets )]} to \p Code to make it well-formed. /// Clang-format conservatively refuses to format files with unmatched brackets /// as it isn't sure where the errors are and so can't correct. /// When editing, it's reasonable to assume code before the cursor is complete. void closeBrackets(std::string &Code, const format::FormatStyle &Style) { … } static StringRef commentMarker(llvm::StringRef Line) { … } llvm::StringRef firstLine(llvm::StringRef Code) { … } llvm::StringRef lastLine(llvm::StringRef Code) { … } // Filename is needed for tooling::Replacement and some overloads of reformat(). // Its value should not affect the outcome. We use the default from reformat(). llvm::StringRef Filename = …; // tooling::Replacement from overlapping StringRefs: From must be part of Code. tooling::Replacement replacement(llvm::StringRef Code, llvm::StringRef From, llvm::StringRef To) { … } // High-level representation of incremental formatting changes. // The changes are made in two steps. // 1) a (possibly-empty) set of changes synthesized by clangd (e.g. adding // comment markers when splitting a line comment with a newline). // 2) a selective clang-format run: // - the "source code" passed to clang format is the code up to the cursor, // a placeholder for the cursor, and some closing brackets // - the formatting is restricted to the cursor and (possibly) other ranges // (e.g. the old line when inserting a newline). // - changes before the cursor are applied, those after are discarded. struct IncrementalChanges { … }; // The two functions below, columnWidth() and columnWidthWithTabs(), were // adapted from similar functions in clang/lib/Format/Encoding.h. // FIXME: Move those functions to clang/include/clang/Format.h and reuse them? // Helper function for columnWidthWithTabs(). inline unsigned columnWidth(StringRef Text) { … } // Returns the number of columns required to display the \p Text on a terminal // with the \p TabWidth. inline unsigned columnWidthWithTabs(StringRef Text, unsigned TabWidth) { … } // After a newline: // - we continue any line-comment that was split // - we format the old line in addition to the cursor // - we represent the cursor with a line comment to preserve the newline IncrementalChanges getIncrementalChangesAfterNewline(llvm::StringRef Code, unsigned Cursor, unsigned TabWidth) { … } IncrementalChanges getIncrementalChanges(llvm::StringRef Code, unsigned Cursor, llvm::StringRef InsertedText, unsigned TabWidth) { … } // Returns equivalent replacements that preserve the correspondence between // OldCursor and NewCursor. If OldCursor lies in a replaced region, that // replacement will be split. std::vector<tooling::Replacement> split(const tooling::Replacements &Replacements, unsigned OldCursor, unsigned NewCursor) { … } } // namespace // We're simulating the following sequence of changes: // - apply the pre-formatting edits (see getIncrementalChanges) // - insert a placeholder for the cursor // - format some of the resulting code // - remove the cursor placeholder again // The replacements we return are produced by composing these. // // The text we actually pass to clang-format is slightly different from this, // e.g. we have to close brackets. We ensure these differences are *after* // all the regions we want to format, and discard changes in them. std::vector<tooling::Replacement> formatIncremental(llvm::StringRef OriginalCode, unsigned OriginalCursor, llvm::StringRef InsertedText, format::FormatStyle Style) { … } unsigned transformCursorPosition(unsigned Offset, const std::vector<tooling::Replacement> &Replacements) { … } } // namespace clangd } // namespace clang