2015-10-01 12:45:06 +02:00
|
|
|
/****************************************************************************
|
2015-06-01 18:51:55 +02:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2015-06-01 18:51:55 +02:00
|
|
|
**
|
|
|
|
|
** 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
|
2016-01-15 14:57:40 +01:00
|
|
|
** 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.
|
2015-06-01 18:51:55 +02:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** 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.
|
2015-06-01 18:51:55 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2015-11-30 09:43:50 +01:00
|
|
|
#include "clangcompletionchunkstotextconverter.h"
|
2015-06-01 18:51:55 +02:00
|
|
|
|
2015-07-14 16:08:14 +02:00
|
|
|
#include <algorithm>
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
2015-06-01 18:51:55 +02:00
|
|
|
namespace ClangCodeModel {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2015-12-11 11:45:05 +01:00
|
|
|
void CompletionChunksToTextConverter::parseChunks(
|
|
|
|
|
const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks)
|
2015-06-01 18:51:55 +02:00
|
|
|
{
|
|
|
|
|
m_text.clear();
|
2015-07-14 16:08:14 +02:00
|
|
|
m_placeholderPositions.clear();
|
|
|
|
|
|
|
|
|
|
m_codeCompletionChunks = codeCompletionChunks;
|
|
|
|
|
|
|
|
|
|
addExtraVerticalSpaceBetweenBraces();
|
|
|
|
|
|
|
|
|
|
std::for_each(m_codeCompletionChunks.cbegin(),
|
|
|
|
|
m_codeCompletionChunks.cend(),
|
|
|
|
|
[this] (const ClangBackEnd::CodeCompletionChunk &chunk)
|
|
|
|
|
{
|
2015-12-11 11:45:05 +01:00
|
|
|
parseDependendOnTheOptionalState(chunk);
|
2015-07-14 16:08:14 +02:00
|
|
|
m_previousCodeCompletionChunk = chunk;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CompletionChunksToTextConverter::setAddPlaceHolderText(bool addPlaceHolderText)
|
|
|
|
|
{
|
|
|
|
|
m_addPlaceHolderText = addPlaceHolderText;
|
|
|
|
|
}
|
2015-06-01 18:51:55 +02:00
|
|
|
|
2015-07-14 16:08:14 +02:00
|
|
|
void CompletionChunksToTextConverter::setAddPlaceHolderPositions(bool addPlaceHolderPositions)
|
|
|
|
|
{
|
|
|
|
|
m_addPlaceHolderPositions = addPlaceHolderPositions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CompletionChunksToTextConverter::setAddResultType(bool addResultType)
|
|
|
|
|
{
|
|
|
|
|
m_addResultType = addResultType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CompletionChunksToTextConverter::setAddSpaces(bool addSpaces)
|
|
|
|
|
{
|
|
|
|
|
m_addSpaces = addSpaces;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-11 11:45:05 +01:00
|
|
|
void CompletionChunksToTextConverter::setAddExtraVerticalSpaceBetweenBraces(
|
|
|
|
|
bool addExtraVerticalSpaceBetweenBraces)
|
2015-07-14 16:08:14 +02:00
|
|
|
{
|
|
|
|
|
m_addExtraVerticalSpaceBetweenBraces = addExtraVerticalSpaceBetweenBraces;
|
2015-06-01 18:51:55 +02:00
|
|
|
}
|
|
|
|
|
|
2015-12-09 14:30:18 +01:00
|
|
|
void CompletionChunksToTextConverter::setEmphasizeOptional(bool emphasizeOptional)
|
2015-08-05 12:07:20 +02:00
|
|
|
{
|
2015-12-09 14:30:18 +01:00
|
|
|
m_emphasizeOptional = emphasizeOptional;
|
2015-08-05 12:07:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CompletionChunksToTextConverter::setAddOptional(bool addOptional)
|
|
|
|
|
{
|
|
|
|
|
m_addOptional = addOptional;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-09 14:30:18 +01:00
|
|
|
void CompletionChunksToTextConverter::setPlaceHolderToEmphasize(int placeHolderNumber)
|
|
|
|
|
{
|
|
|
|
|
m_placeHolderPositionToEmphasize = placeHolderNumber;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-12 11:32:16 +02:00
|
|
|
void CompletionChunksToTextConverter::setCompletionKind(const ClangBackEnd::CodeCompletion::Kind kind)
|
|
|
|
|
{
|
|
|
|
|
m_codeCompletionKind = kind;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-18 09:51:00 +01:00
|
|
|
void CompletionChunksToTextConverter::setupForKeywords()
|
|
|
|
|
{
|
|
|
|
|
setAddPlaceHolderPositions(true);
|
|
|
|
|
setAddSpaces(true);
|
|
|
|
|
setAddExtraVerticalSpaceBetweenBraces(true);
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-01 18:51:55 +02:00
|
|
|
const QString &CompletionChunksToTextConverter::text() const
|
|
|
|
|
{
|
|
|
|
|
return m_text;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-14 16:08:14 +02:00
|
|
|
const std::vector<int> &CompletionChunksToTextConverter::placeholderPositions() const
|
|
|
|
|
{
|
|
|
|
|
return m_placeholderPositions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CompletionChunksToTextConverter::hasPlaceholderPositions() const
|
|
|
|
|
{
|
|
|
|
|
return m_placeholderPositions.size() > 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-18 11:22:39 +01:00
|
|
|
QString CompletionChunksToTextConverter::convertToFunctionSignatureWithHtml(
|
2015-12-09 14:30:18 +01:00
|
|
|
const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks,
|
2017-06-12 11:32:16 +02:00
|
|
|
ClangBackEnd::CodeCompletion::Kind codeCompletionKind,
|
2015-12-09 14:30:18 +01:00
|
|
|
int parameterToEmphasize)
|
2015-07-14 16:08:14 +02:00
|
|
|
{
|
|
|
|
|
CompletionChunksToTextConverter converter;
|
|
|
|
|
converter.setAddPlaceHolderText(true);
|
|
|
|
|
converter.setAddResultType(true);
|
2015-12-09 14:30:18 +01:00
|
|
|
|
2016-01-18 11:22:39 +01:00
|
|
|
converter.setTextFormat(TextFormat::Html);
|
2015-08-05 12:07:20 +02:00
|
|
|
converter.setAddOptional(true);
|
2015-12-09 14:30:18 +01:00
|
|
|
converter.setEmphasizeOptional(true);
|
|
|
|
|
|
|
|
|
|
converter.setAddPlaceHolderPositions(true);
|
|
|
|
|
converter.setPlaceHolderToEmphasize(parameterToEmphasize);
|
2017-06-12 11:32:16 +02:00
|
|
|
converter.setCompletionKind(codeCompletionKind);
|
2015-07-14 16:08:14 +02:00
|
|
|
|
|
|
|
|
converter.parseChunks(codeCompletionChunks);
|
|
|
|
|
|
|
|
|
|
return converter.text();
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-11 11:45:05 +01:00
|
|
|
QString CompletionChunksToTextConverter::convertToName(
|
|
|
|
|
const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks)
|
2015-06-01 18:51:55 +02:00
|
|
|
{
|
|
|
|
|
CompletionChunksToTextConverter converter;
|
|
|
|
|
|
|
|
|
|
converter.parseChunks(codeCompletionChunks);
|
|
|
|
|
|
|
|
|
|
return converter.text();
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-18 11:22:39 +01:00
|
|
|
QString CompletionChunksToTextConverter::convertToToolTipWithHtml(
|
2017-06-12 11:32:16 +02:00
|
|
|
const ClangBackEnd::CodeCompletionChunks &codeCompletionChunks,
|
|
|
|
|
ClangBackEnd::CodeCompletion::Kind codeCompletionKind)
|
2015-07-15 16:59:19 +02:00
|
|
|
{
|
|
|
|
|
CompletionChunksToTextConverter converter;
|
|
|
|
|
converter.setAddPlaceHolderText(true);
|
|
|
|
|
converter.setAddSpaces(true);
|
|
|
|
|
converter.setAddExtraVerticalSpaceBetweenBraces(true);
|
2015-08-05 12:07:20 +02:00
|
|
|
converter.setAddOptional(true);
|
2016-01-18 11:22:39 +01:00
|
|
|
converter.setTextFormat(TextFormat::Html);
|
2015-12-09 14:30:18 +01:00
|
|
|
converter.setEmphasizeOptional(true);
|
2015-08-05 12:07:20 +02:00
|
|
|
converter.setAddResultType(true);
|
2017-06-12 11:32:16 +02:00
|
|
|
converter.setCompletionKind(codeCompletionKind);
|
2015-07-15 16:59:19 +02:00
|
|
|
|
|
|
|
|
converter.parseChunks(codeCompletionChunks);
|
|
|
|
|
|
|
|
|
|
return converter.text();
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-11 11:45:05 +01:00
|
|
|
void CompletionChunksToTextConverter::parse(
|
|
|
|
|
const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk)
|
2015-06-01 18:51:55 +02:00
|
|
|
{
|
2015-06-16 11:56:00 +02:00
|
|
|
using ClangBackEnd::CodeCompletionChunk;
|
2015-06-01 18:51:55 +02:00
|
|
|
|
|
|
|
|
switch (codeCompletionChunk.kind()) {
|
|
|
|
|
case CodeCompletionChunk::ResultType: parseResultType(codeCompletionChunk.text()); break;
|
2017-04-28 17:46:40 +02:00
|
|
|
// 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;
|
2015-07-14 16:08:14 +02:00
|
|
|
case CodeCompletionChunk::LeftParen: parseLeftParen(codeCompletionChunk); break;
|
|
|
|
|
case CodeCompletionChunk::LeftBrace: parseLeftBrace(codeCompletionChunk); break;
|
2015-06-01 18:51:55 +02:00
|
|
|
default: parseText(codeCompletionChunk.text()); break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-11 11:45:05 +01:00
|
|
|
void CompletionChunksToTextConverter::parseDependendOnTheOptionalState(
|
|
|
|
|
const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk)
|
|
|
|
|
{
|
|
|
|
|
wrapInCursiveTagIfOptional(codeCompletionChunk);
|
|
|
|
|
|
|
|
|
|
if (isNotOptionalOrAddOptionals(codeCompletionChunk))
|
|
|
|
|
parse(codeCompletionChunk);
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-01 18:51:55 +02:00
|
|
|
void CompletionChunksToTextConverter::parseResultType(const Utf8String &resultTypeText)
|
|
|
|
|
{
|
2015-07-14 16:08:14 +02:00
|
|
|
if (m_addResultType)
|
2016-01-18 11:22:39 +01:00
|
|
|
m_text += inDesiredTextFormat(resultTypeText) + QChar(QChar::Space);
|
2015-06-01 18:51:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CompletionChunksToTextConverter::parseText(const Utf8String &text)
|
|
|
|
|
{
|
2015-07-15 11:18:54 +02:00
|
|
|
if (canAddSpace()
|
|
|
|
|
&& m_previousCodeCompletionChunk.kind() == ClangBackEnd::CodeCompletionChunk::RightBrace) {
|
2015-07-14 16:08:14 +02:00
|
|
|
m_text += QChar(QChar::Space);
|
2015-07-15 11:18:54 +02:00
|
|
|
}
|
2015-07-14 16:08:14 +02:00
|
|
|
|
2016-01-18 11:22:39 +01:00
|
|
|
m_text += inDesiredTextFormat(text);
|
2015-06-01 18:51:55 +02:00
|
|
|
}
|
|
|
|
|
|
2015-12-11 11:45:05 +01:00
|
|
|
void CompletionChunksToTextConverter::wrapInCursiveTagIfOptional(
|
|
|
|
|
const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk)
|
2015-06-01 18:51:55 +02:00
|
|
|
{
|
2015-08-05 12:07:20 +02:00
|
|
|
if (m_addOptional) {
|
2016-01-18 11:22:39 +01:00
|
|
|
if (m_emphasizeOptional && m_textFormat == TextFormat::Html) {
|
2015-12-11 11:45:05 +01:00
|
|
|
if (!m_previousCodeCompletionChunk.isOptional() && codeCompletionChunk.isOptional())
|
|
|
|
|
m_text += QStringLiteral("<i>");
|
|
|
|
|
else if (m_previousCodeCompletionChunk.isOptional() && !codeCompletionChunk.isOptional())
|
|
|
|
|
m_text += QStringLiteral("</i>");
|
|
|
|
|
}
|
2015-08-05 12:07:20 +02:00
|
|
|
}
|
2015-06-01 18:51:55 +02:00
|
|
|
}
|
|
|
|
|
|
2015-12-11 11:45:05 +01:00
|
|
|
void CompletionChunksToTextConverter::parsePlaceHolder(
|
|
|
|
|
const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk)
|
2015-07-14 16:08:14 +02:00
|
|
|
{
|
2015-12-09 17:51:14 +01:00
|
|
|
if (m_addPlaceHolderText) {
|
2016-01-18 11:22:39 +01:00
|
|
|
appendText(inDesiredTextFormat(codeCompletionChunk.text()),
|
2015-12-09 17:51:14 +01:00
|
|
|
emphasizeCurrentPlaceHolder());
|
|
|
|
|
}
|
2015-07-14 16:08:14 +02:00
|
|
|
|
|
|
|
|
if (m_addPlaceHolderPositions)
|
|
|
|
|
m_placeholderPositions.push_back(m_text.size());
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-11 11:45:05 +01:00
|
|
|
void CompletionChunksToTextConverter::parseLeftParen(
|
|
|
|
|
const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk)
|
2015-07-14 16:08:14 +02:00
|
|
|
{
|
2015-07-15 11:18:54 +02:00
|
|
|
if (canAddSpace())
|
2015-07-14 16:08:14 +02:00
|
|
|
m_text += QChar(QChar::Space);
|
|
|
|
|
m_text += codeCompletionChunk.text().toString();
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-11 11:45:05 +01:00
|
|
|
void CompletionChunksToTextConverter::parseLeftBrace(
|
|
|
|
|
const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk)
|
2015-07-14 16:08:14 +02:00
|
|
|
{
|
2015-07-15 11:18:54 +02:00
|
|
|
if (canAddSpace())
|
2015-07-14 16:08:14 +02:00
|
|
|
m_text += QChar(QChar::Space);
|
|
|
|
|
|
|
|
|
|
m_text += codeCompletionChunk.text().toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CompletionChunksToTextConverter::addExtraVerticalSpaceBetweenBraces()
|
|
|
|
|
{
|
|
|
|
|
if (m_addExtraVerticalSpaceBetweenBraces)
|
|
|
|
|
addExtraVerticalSpaceBetweenBraces(m_codeCompletionChunks.begin());
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-11 11:45:05 +01:00
|
|
|
void CompletionChunksToTextConverter::addExtraVerticalSpaceBetweenBraces(
|
|
|
|
|
const ClangBackEnd::CodeCompletionChunks::iterator &begin)
|
2015-07-14 16:08:14 +02:00
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-19 15:34:31 +01:00
|
|
|
QString CompletionChunksToTextConverter::inDesiredTextFormat(const Utf8String &text) const
|
2016-01-18 11:22:39 +01:00
|
|
|
{
|
|
|
|
|
if (m_textFormat == TextFormat::Html)
|
|
|
|
|
return text.toString().toHtmlEscaped();
|
|
|
|
|
else
|
|
|
|
|
return text.toString();
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-09 14:30:18 +01:00
|
|
|
bool CompletionChunksToTextConverter::emphasizeCurrentPlaceHolder() const
|
|
|
|
|
{
|
|
|
|
|
if (m_addPlaceHolderPositions) {
|
2016-08-24 14:00:59 +02:00
|
|
|
const uint currentPlaceHolderPosition = uint(m_placeholderPositions.size() + 1);
|
2015-12-09 14:30:18 +01:00
|
|
|
return uint(m_placeHolderPositionToEmphasize) == currentPlaceHolderPosition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-18 11:22:39 +01:00
|
|
|
void CompletionChunksToTextConverter::setTextFormat(TextFormat textFormat)
|
|
|
|
|
{
|
|
|
|
|
m_textFormat = textFormat;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-09 14:30:18 +01:00
|
|
|
void CompletionChunksToTextConverter::appendText(const QString &text, bool boldFormat)
|
|
|
|
|
{
|
2016-01-18 11:22:39 +01:00
|
|
|
if (boldFormat && m_textFormat == TextFormat::Html)
|
2015-12-09 14:30:18 +01:00
|
|
|
m_text += QStringLiteral("<b>") + text + QStringLiteral("</b>");
|
|
|
|
|
else
|
|
|
|
|
m_text += text;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-15 11:18:54 +02:00
|
|
|
bool CompletionChunksToTextConverter::canAddSpace() const
|
|
|
|
|
{
|
|
|
|
|
return m_addSpaces
|
|
|
|
|
&& m_previousCodeCompletionChunk.kind() != ClangBackEnd::CodeCompletionChunk::HorizontalSpace
|
2017-06-12 11:32:16 +02:00
|
|
|
&& m_previousCodeCompletionChunk.kind() != ClangBackEnd::CodeCompletionChunk::RightAngle
|
|
|
|
|
&& m_codeCompletionKind != ClangBackEnd::CodeCompletion::FunctionCompletionKind;
|
2015-07-15 11:18:54 +02:00
|
|
|
}
|
|
|
|
|
|
2015-12-11 11:45:05 +01:00
|
|
|
bool CompletionChunksToTextConverter::isNotOptionalOrAddOptionals(
|
|
|
|
|
const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk) const
|
|
|
|
|
{
|
|
|
|
|
return !codeCompletionChunk.isOptional() || m_addOptional;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-01 18:51:55 +02:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace ClangCodeModel
|
|
|
|
|
|