mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 20:30:14 +01:00
Support multi-file compilation, and in particular imports of files from the prelude, in `carbon language_server`. In order to properly interface with `CompileDriver`, also switch over to building a proper VFS from the documents we're given. Assisted-by: Gemini via Antigravity
106 lines
3.1 KiB
C++
106 lines
3.1 KiB
C++
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#include "toolchain/driver/format_subcommand.h"
|
|
|
|
#include <string>
|
|
|
|
#include "common/raw_string_ostream.h"
|
|
#include "toolchain/base/shared_value_stores.h"
|
|
#include "toolchain/diagnostics/consumer.h"
|
|
#include "toolchain/format/format.h"
|
|
#include "toolchain/lex/lex.h"
|
|
#include "toolchain/source/source_buffer.h"
|
|
|
|
namespace Carbon {
|
|
|
|
auto FormatOptions::Build(CommandLine::CommandBuilder& b) -> void {
|
|
b.AddStringPositionalArg(
|
|
{
|
|
.name = "FILE",
|
|
.help = R"""(
|
|
The input Carbon source file(s) to format.
|
|
)""",
|
|
},
|
|
[&](auto& arg_b) {
|
|
arg_b.Required(true);
|
|
arg_b.Append(&input_filenames);
|
|
});
|
|
b.AddStringOption(
|
|
{
|
|
.name = "output",
|
|
.value_name = "FILE",
|
|
.help = R"""(
|
|
The output filename for formatted output.
|
|
|
|
By default, the input file is formatted. Passing `--output=-` will write the
|
|
output to stdout.
|
|
|
|
Not valid when multiple files are passed for formatting.
|
|
)""",
|
|
},
|
|
[&](auto& arg_b) { arg_b.Set(&output_filename); });
|
|
}
|
|
|
|
static constexpr CommandLine::CommandInfo SubcommandInfo = {
|
|
.name = "format",
|
|
.help = R"""(
|
|
Format Carbon source code.
|
|
)""",
|
|
};
|
|
|
|
FormatSubcommand::FormatSubcommand() : DriverSubcommand(SubcommandInfo) {}
|
|
|
|
auto FormatSubcommand::Run(DriverEnv& driver_env) -> DriverResult {
|
|
DriverResult result = {.success = true};
|
|
if (options_.input_filenames.size() > 1 &&
|
|
!options_.output_filename.empty()) {
|
|
CARBON_DIAGNOSTIC(FormatMultipleFilesToOneOutput, Error,
|
|
"multiple input files are being provided; --output only "
|
|
"works with one input");
|
|
driver_env.emitter.Emit(FormatMultipleFilesToOneOutput);
|
|
result.success = false;
|
|
return result;
|
|
}
|
|
|
|
auto mark_per_file_error = [&]() {
|
|
result.success = false;
|
|
result.per_file_success.back().second = false;
|
|
};
|
|
|
|
for (auto& f : options_.input_filenames) {
|
|
// Push a result, which we'll update on failure.
|
|
result.per_file_success.push_back({f.str(), true});
|
|
|
|
// TODO: Consider refactoring this for sharing with compile.
|
|
// TODO: Decide what to do with `-` when there are multiple arguments.
|
|
auto source = SourceBuffer::MakeFromFileOrStdin(*driver_env.fs, f,
|
|
*driver_env.consumer);
|
|
if (!source) {
|
|
mark_per_file_error();
|
|
continue;
|
|
}
|
|
SharedValueStores value_stores;
|
|
Lex::LexOptions lex_options;
|
|
lex_options.consumer = driver_env.consumer;
|
|
auto tokens = Lex::Lex(value_stores, *source, lex_options);
|
|
|
|
RawStringOstream buffer;
|
|
if (Format::Format(tokens, buffer)) {
|
|
// TODO: Figure out a multi-file output setup that supports good
|
|
// multi-file testing.
|
|
// TODO: Use --output values (and default to overwrite).
|
|
*driver_env.output_stream << buffer.TakeStr();
|
|
} else {
|
|
buffer.clear();
|
|
mark_per_file_error();
|
|
*driver_env.output_stream << source->text();
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
} // namespace Carbon
|