/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "clangcompletionchunkstotextconverter.h" #include #include #include namespace ClangCodeModel { namespace Internal { void CompletionChunksToTextConverter::parseChunks( const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks) { m_text.clear(); m_placeholderPositions.clear(); m_codeCompletionChunks = codeCompletionChunks; addExtraVerticalSpaceBetweenBraces(); std::for_each(m_codeCompletionChunks.cbegin(), m_codeCompletionChunks.cend(), [this] (const ClangBackEnd::CodeCompletionChunk &chunk) { parseDependentOnTheOptionalState(chunk); m_previousCodeCompletionChunk = chunk; }); } void CompletionChunksToTextConverter::setAddPlaceHolderText(bool addPlaceHolderText) { m_addPlaceHolderText = addPlaceHolderText; } void CompletionChunksToTextConverter::setAddPlaceHolderPositions(bool addPlaceHolderPositions) { m_addPlaceHolderPositions = addPlaceHolderPositions; } void CompletionChunksToTextConverter::setAddResultType(bool addResultType) { m_addResultType = addResultType; } void CompletionChunksToTextConverter::setAddSpaces(bool addSpaces) { m_addSpaces = addSpaces; } void CompletionChunksToTextConverter::setHonorVerticalSpace(bool honor) { m_honorVerticalSpace = honor; } void CompletionChunksToTextConverter::setAddExtraVerticalSpaceBetweenBraces( bool addExtraVerticalSpaceBetweenBraces) { m_addExtraVerticalSpaceBetweenBraces = addExtraVerticalSpaceBetweenBraces; } void CompletionChunksToTextConverter::setEmphasizeOptional(bool emphasizeOptional) { m_emphasizeOptional = emphasizeOptional; } void CompletionChunksToTextConverter::setAddOptional(bool addOptional) { m_addOptional = addOptional; } void CompletionChunksToTextConverter::setPlaceHolderToEmphasize(int placeHolderNumber) { m_placeHolderPositionToEmphasize = placeHolderNumber; } void CompletionChunksToTextConverter::setCompletionKind(const ClangBackEnd::CodeCompletion::Kind kind) { m_codeCompletionKind = kind; } void CompletionChunksToTextConverter::setupForKeywords() { setAddPlaceHolderPositions(true); setAddSpaces(true); setAddExtraVerticalSpaceBetweenBraces(true); } const QString &CompletionChunksToTextConverter::text() const { return m_text; } const std::vector &CompletionChunksToTextConverter::placeholderPositions() const { return m_placeholderPositions; } bool CompletionChunksToTextConverter::hasPlaceholderPositions() const { return m_placeholderPositions.size() > 0; } QString CompletionChunksToTextConverter::convertToFunctionSignatureWithHtml( const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks, ClangBackEnd::CodeCompletion::Kind codeCompletionKind, int parameterToEmphasize) { CompletionChunksToTextConverter converter; converter.setAddPlaceHolderText(true); converter.setAddResultType(true); converter.setTextFormat(TextFormat::Html); converter.setAddOptional(true); converter.setEmphasizeOptional(true); converter.setAddPlaceHolderPositions(true); converter.setPlaceHolderToEmphasize(parameterToEmphasize); converter.setCompletionKind(codeCompletionKind); converter.parseChunks(codeCompletionChunks); return converter.text(); } QString CompletionChunksToTextConverter::convertToName( const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks) { CompletionChunksToTextConverter converter; converter.setHonorVerticalSpace(false); converter.parseChunks(codeCompletionChunks); return converter.text(); } QString CompletionChunksToTextConverter::convertToToolTipWithHtml( const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks, ClangBackEnd::CodeCompletion::Kind codeCompletionKind) { CompletionChunksToTextConverter converter; converter.setAddPlaceHolderText(true); converter.setAddSpaces(true); converter.setAddExtraVerticalSpaceBetweenBraces(true); converter.setAddOptional(true); converter.setTextFormat(TextFormat::Html); converter.setEmphasizeOptional(true); converter.setAddResultType(true); converter.setCompletionKind(codeCompletionKind); converter.parseChunks(codeCompletionChunks); return converter.text(); } void CompletionChunksToTextConverter::parse( const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) { using ClangBackEnd::CodeCompletionChunk; switch (codeCompletionChunk.kind) { case CodeCompletionChunk::ResultType: parseResultType(codeCompletionChunk.text); break; // Do not rely on CurrentParameter because it might be wrong for // invalid code. Instead, handle it as PlaceHolder. case CodeCompletionChunk::CurrentParameter: case CodeCompletionChunk::Placeholder: parsePlaceHolder(codeCompletionChunk); break; case CodeCompletionChunk::LeftParen: parseLeftParen(codeCompletionChunk); break; case CodeCompletionChunk::LeftBrace: parseLeftBrace(codeCompletionChunk); break; case CodeCompletionChunk::VerticalSpace: if (!m_honorVerticalSpace) break; Q_FALLTHROUGH(); default: parseText(codeCompletionChunk.text); break; } } void CompletionChunksToTextConverter::parseDependentOnTheOptionalState( const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) { wrapInCursiveTagIfOptional(codeCompletionChunk); if (isNotOptionalOrAddOptionals(codeCompletionChunk)) parse(codeCompletionChunk); } void CompletionChunksToTextConverter::parseResultType(const Utf8String &resultTypeText) { if (m_addResultType) m_text += inDesiredTextFormat(resultTypeText) + QChar(QChar::Space); } void CompletionChunksToTextConverter::parseText(const Utf8String &text) { if (canAddSpace() && m_previousCodeCompletionChunk.kind == ClangBackEnd::CodeCompletionChunk::RightBrace) { m_text += QChar(QChar::Space); } m_text += inDesiredTextFormat(text); } void CompletionChunksToTextConverter::wrapInCursiveTagIfOptional( const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) { if (m_addOptional) { if (m_emphasizeOptional && m_textFormat == TextFormat::Html) { if (!m_previousCodeCompletionChunk.isOptional && codeCompletionChunk.isOptional) m_text += QStringLiteral(""); else if (m_previousCodeCompletionChunk.isOptional && !codeCompletionChunk.isOptional) m_text += QStringLiteral(""); } } } void CompletionChunksToTextConverter::parsePlaceHolder( const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) { if (m_addPlaceHolderText) { appendText(inDesiredTextFormat(codeCompletionChunk.text), emphasizeCurrentPlaceHolder()); } if (m_addPlaceHolderPositions) m_placeholderPositions.push_back(m_text.size()); } void CompletionChunksToTextConverter::parseLeftParen( const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) { if (canAddSpace()) m_text += QChar(QChar::Space); m_text += codeCompletionChunk.text.toString(); } void CompletionChunksToTextConverter::parseLeftBrace( const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) { if (canAddSpace()) m_text += QChar(QChar::Space); m_text += codeCompletionChunk.text.toString(); } void CompletionChunksToTextConverter::addExtraVerticalSpaceBetweenBraces() { if (m_addExtraVerticalSpaceBetweenBraces) addExtraVerticalSpaceBetweenBraces(m_codeCompletionChunks.begin()); } void CompletionChunksToTextConverter::addExtraVerticalSpaceBetweenBraces( const ClangBackEnd::CodeCompletionChunks::iterator &begin) { using ClangBackEnd::CodeCompletionChunk; const auto leftBraceCompare = [] (const CodeCompletionChunk &chunk) { return chunk.kind == CodeCompletionChunk::LeftBrace; }; const auto rightBraceCompare = [] (const CodeCompletionChunk &chunk) { return chunk.kind == CodeCompletionChunk::RightBrace; }; const auto verticalSpaceCompare = [] (const CodeCompletionChunk &chunk) { return chunk.kind == CodeCompletionChunk::VerticalSpace; }; auto leftBrace = std::find_if(begin, m_codeCompletionChunks.end(), leftBraceCompare); if (leftBrace != m_codeCompletionChunks.end()) { auto rightBrace = std::find_if(leftBrace, m_codeCompletionChunks.end(), rightBraceCompare); if (rightBrace != m_codeCompletionChunks.end()) { auto verticalSpaceCount = std::count_if(leftBrace, rightBrace, verticalSpaceCompare); if (verticalSpaceCount <= 1) { auto distance = std::distance(leftBrace, rightBrace); CodeCompletionChunk verticalSpaceChunck(CodeCompletionChunk::VerticalSpace, Utf8StringLiteral("\n")); auto verticalSpace = m_codeCompletionChunks.insert(std::next(leftBrace), verticalSpaceChunck); std::advance(verticalSpace, distance); rightBrace = verticalSpace; } auto begin = std::next(rightBrace); if (begin != m_codeCompletionChunks.end()) addExtraVerticalSpaceBetweenBraces(begin); } } } QString CompletionChunksToTextConverter::inDesiredTextFormat(const Utf8String &text) const { if (m_textFormat == TextFormat::Html) return text.toString().toHtmlEscaped(); else return text.toString(); } bool CompletionChunksToTextConverter::emphasizeCurrentPlaceHolder() const { if (m_addPlaceHolderPositions) { const uint currentPlaceHolderPosition = uint(m_placeholderPositions.size() + 1); return uint(m_placeHolderPositionToEmphasize) == currentPlaceHolderPosition; } return false; } void CompletionChunksToTextConverter::setTextFormat(TextFormat textFormat) { m_textFormat = textFormat; } void CompletionChunksToTextConverter::appendText(const QString &text, bool boldFormat) { if (boldFormat && m_textFormat == TextFormat::Html) m_text += QStringLiteral("") + text + QStringLiteral(""); else m_text += text; } bool CompletionChunksToTextConverter::canAddSpace() const { return m_addSpaces && m_previousCodeCompletionChunk.kind != ClangBackEnd::CodeCompletionChunk::HorizontalSpace && m_previousCodeCompletionChunk.kind != ClangBackEnd::CodeCompletionChunk::RightAngle && m_codeCompletionKind != ClangBackEnd::CodeCompletion::FunctionCompletionKind; } bool CompletionChunksToTextConverter::isNotOptionalOrAddOptionals( const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) const { return !codeCompletionChunk.isOptional || m_addOptional; } } // namespace Internal } // namespace ClangCodeModel