diff options
Diffstat (limited to 'src/qmlls/qqmlformatting.cpp')
-rw-r--r-- | src/qmlls/qqmlformatting.cpp | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/src/qmlls/qqmlformatting.cpp b/src/qmlls/qqmlformatting.cpp new file mode 100644 index 0000000000..82313f1c65 --- /dev/null +++ b/src/qmlls/qqmlformatting.cpp @@ -0,0 +1,95 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include <qqmlformatting_p.h> +#include <qqmlcodemodel_p.h> +#include <qqmllsutils_p.h> + +#include <QtQmlDom/private/qqmldomitem_p.h> +#include <QtQmlDom/private/qqmldomindentinglinewriter_p.h> +#include <QtQmlDom/private/qqmldomoutwriter_p.h> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(formatLog, "qt.languageserver.formatting") + +QQmlDocumentFormatting::QQmlDocumentFormatting(QmlLsp::QQmlCodeModel *codeModel) + : QQmlBaseModule(codeModel) +{ +} + +QString QQmlDocumentFormatting::name() const +{ + return u"QQmlDocumentFormatting"_s; +} + +void QQmlDocumentFormatting::registerHandlers(QLanguageServer *, QLanguageServerProtocol *protocol) +{ + protocol->registerDocumentFormattingRequestHandler(getRequestHandler()); +} + +void QQmlDocumentFormatting::setupCapabilities( + const QLspSpecification::InitializeParams &, + QLspSpecification::InitializeResult &serverCapabilities) +{ + // TODO: Allow customized formatting in future + serverCapabilities.capabilities.documentFormattingProvider = true; +} + +void QQmlDocumentFormatting::process(RequestPointerArgument request) +{ + QList<QLspSpecification::TextEdit> result; + ResponseScopeGuard guard(result, request->m_response); + + using namespace QQmlJS::Dom; + QmlLsp::OpenDocument doc = m_codeModel->openDocumentByUrl( + QQmlLSUtils::lspUriToQmlUrl(request->m_parameters.textDocument.uri)); + + DomItem file = doc.snapshot.doc.fileObject(GoTo::MostLikely); + if (!file) { + guard.setError(QQmlLSUtilsErrorMessage{ + 0, u"Could not find the file %1"_s.arg(doc.snapshot.doc.canonicalFilePath()) }); + return; + } + if (!file.field(Fields::isValid).value().toBool(false)) { + guard.setError(QQmlLSUtilsErrorMessage{ 0, u"Cannot format invalid documents!"_s }); + return; + } + if (auto envPtr = file.environment().ownerAs<DomEnvironment>()) + envPtr->clearReferenceCache(); + + auto qmlFile = file.ownerAs<QmlFile>(); + if (!qmlFile || !qmlFile->isValid()) { + file.iterateErrors( + [](const DomItem &, const ErrorMessage &msg) { + errorToQDebug(msg); + return true; + }, + true); + guard.setError(QQmlLSUtilsErrorMessage{ + 0, u"Failed to parse %1"_s.arg(file.canonicalFilePath()) }); + return; + } + + // TODO: implement formatting options + // For now, qmlformat's default options. + LineWriterOptions options; + options.updateOptions = LineWriterOptions::Update::None; + options.attributesSequence = LineWriterOptions::AttributesSequence::Preserve; + + QLspSpecification::TextEdit formattedText; + LineWriter lw([&formattedText](QStringView s) {formattedText.newText += s.toUtf8(); }, QString(), options); + OutWriter ow(lw); + file.writeOutForFile(ow, WriteOutCheck::None); + ow.flush(); + const auto &code = qmlFile->code(); + const auto [endLine, endColumn] = QQmlLSUtils::textRowAndColumnFrom(code, code.length()); + + Q_UNUSED(endColumn); + formattedText.range = QLspSpecification::Range{ QLspSpecification::Position{ 0, 0 }, + QLspSpecification::Position{ endLine + 1, 0 } }; + + result.append(formattedText); +} + +QT_END_NAMESPACE |