summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2019-07-25 15:06:35 +0000
committerHans Wennborg <hans@hanshq.net>2019-07-25 15:06:35 +0000
commitcf2c5ed5376b6687100a00247a326dd601f47b40 (patch)
tree84ac43c3d4ddf3cef655d8333a4089a61431b227
parent40ba6399880eaa66dbfac60b511d80af1c67ac25 (diff)
Merging r366811, r366880, r366900, r366991 and r366992:
------------------------------------------------------------------------ r366811 | sammccall | 2019-07-23 16:30:28 +0200 (Tue, 23 Jul 2019) | 9 lines [clangd] Log version, cwd, args, and transport on startup. NFC Reviewers: hokein Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D65146 ------------------------------------------------------------------------ ------------------------------------------------------------------------ r366880 | sammccall | 2019-07-24 11:33:27 +0200 (Wed, 24 Jul 2019) | 9 lines [clangd] Reformat use of cl::opt: use unqualified name and don't bin-pack attributes. NFC Reviewers: kadircet Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D65154 ------------------------------------------------------------------------ ------------------------------------------------------------------------ r366900 | sammccall | 2019-07-24 14:41:52 +0200 (Wed, 24 Jul 2019) | 16 lines [clangd] Add categories to help options, and only show clangd options. Summary: Restricting the categories prevents extra unwanted options from creeping into help (D60663), and removes a bunch of noise from --help-hidden. While here, remove `static` from the opts in favor of an anon namespace, to reduce the noise level. Reviewers: hokein Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D65200 ------------------------------------------------------------------------ ------------------------------------------------------------------------ r366991 | sammccall | 2019-07-25 09:54:48 +0200 (Thu, 25 Jul 2019) | 13 lines [clangd] Also accept flags from CLANGD_FLAGS variable. This simplifies various workflows, particularly in debugging/development. e.g. editors will tend to propagate flags, so you can run `env CLANGD_FLAGS=-input-mirror-file=/tmp/mirror vim foo.cc` rather than change the configuration in a persistent way. (This also gives us a generic lever when we don't know how to customize the flags in some particular LSP client). While here, add a test for this and other startup logging, and fix a couple of direct writes to errs() that should have been logs. Differential Revision: https://reviews.llvm.org/D65153 ------------------------------------------------------------------------ ------------------------------------------------------------------------ r366992 | sammccall | 2019-07-25 10:00:54 +0200 (Thu, 25 Jul 2019) | 9 lines [clangd] Provide help text to users who run `clangd` in a terminal. Reviewers: hokein Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D65201 ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/branches/release_90@367025 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--clangd/index/Serialization.cpp4
-rw-r--r--clangd/test/log.test9
-rw-r--r--clangd/tool/ClangdMain.cpp543
3 files changed, 341 insertions, 215 deletions
diff --git a/clangd/index/Serialization.cpp b/clangd/index/Serialization.cpp
index 188a5cc1..90520fdc 100644
--- a/clangd/index/Serialization.cpp
+++ b/clangd/index/Serialization.cpp
@@ -690,7 +690,7 @@ std::unique_ptr<SymbolIndex> loadIndex(llvm::StringRef SymbolFilename,
trace::Span OverallTracer("LoadIndex");
auto Buffer = llvm::MemoryBuffer::getFile(SymbolFilename);
if (!Buffer) {
- llvm::errs() << "Can't open " << SymbolFilename << "\n";
+ elog("Can't open {0}", SymbolFilename);
return nullptr;
}
@@ -707,7 +707,7 @@ std::unique_ptr<SymbolIndex> loadIndex(llvm::StringRef SymbolFilename,
if (I->Relations)
Relations = std::move(*I->Relations);
} else {
- llvm::errs() << "Bad Index: " << llvm::toString(I.takeError()) << "\n";
+ elog("Bad Index: {0}", I.takeError());
return nullptr;
}
}
diff --git a/clangd/test/log.test b/clangd/test/log.test
new file mode 100644
index 00000000..7f17f072
--- /dev/null
+++ b/clangd/test/log.test
@@ -0,0 +1,9 @@
+# RUN: not env CLANGD_FLAGS=-index-file=no-such-index clangd -lit-test </dev/null 2>&1 >/dev/null | FileCheck %s
+CHECK: I[{{.*}}] clangd version {{.*}}
+CHECK: Working directory: {{.*}}
+CHECK: argv[0]: clangd
+CHECK: argv[1]: -lit-test
+CHECK: CLANGD_FLAGS: -index-file=no-such-index
+CHECK: E[{{.*}}] Can't open no-such-index
+CHECK: Starting LSP over stdin/stdout
+
diff --git a/clangd/tool/ClangdMain.cpp b/clangd/tool/ClangdMain.cpp
index 5db3d5c2..840f3d64 100644
--- a/clangd/tool/ClangdMain.cpp
+++ b/clangd/tool/ClangdMain.cpp
@@ -22,6 +22,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetSelect.h"
@@ -35,129 +36,165 @@
namespace clang {
namespace clangd {
+namespace {
+
+using llvm::cl::cat;
+using llvm::cl::CommaSeparated;
+using llvm::cl::desc;
+using llvm::cl::Hidden;
+using llvm::cl::init;
+using llvm::cl::list;
+using llvm::cl::opt;
+using llvm::cl::OptionCategory;
+using llvm::cl::values;
+
+// All flags must be placed in a category, or they will be shown neither in
+// --help, nor --help-hidden!
+OptionCategory CompileCommands("clangd compilation flags options");
+OptionCategory Features("clangd feature options");
+OptionCategory Misc("clangd miscellaneous options");
+OptionCategory Protocol("clangd protocol and logging options");
+const OptionCategory *ClangdCategories[] = {&Features, &Protocol,
+ &CompileCommands, &Misc};
-static llvm::cl::opt<Path> CompileCommandsDir(
+enum CompileArgsFrom { LSPCompileArgs, FilesystemCompileArgs };
+opt<CompileArgsFrom> CompileArgsFrom{
+ "compile_args_from",
+ cat(CompileCommands),
+ desc("The source of compile commands"),
+ values(clEnumValN(LSPCompileArgs, "lsp",
+ "All compile commands come from LSP and "
+ "'compile_commands.json' files are ignored"),
+ clEnumValN(FilesystemCompileArgs, "filesystem",
+ "All compile commands come from the "
+ "'compile_commands.json' files")),
+ init(FilesystemCompileArgs),
+ Hidden,
+};
+
+opt<Path> CompileCommandsDir{
"compile-commands-dir",
- llvm::cl::desc("Specify a path to look for compile_commands.json. If path "
- "is invalid, clangd will look in the current directory and "
- "parent paths of each source file"));
+ cat(CompileCommands),
+ desc("Specify a path to look for compile_commands.json. If path "
+ "is invalid, clangd will look in the current directory and "
+ "parent paths of each source file"),
+};
-static llvm::cl::opt<unsigned>
- WorkerThreadsCount("j",
- llvm::cl::desc("Number of async workers used by clangd"),
- llvm::cl::init(getDefaultAsyncThreadsCount()));
+opt<Path> ResourceDir{
+ "resource-dir",
+ cat(CompileCommands),
+ desc("Directory for system clang headers"),
+ init(""),
+ Hidden,
+};
-// FIXME: also support "plain" style where signatures are always omitted.
-enum CompletionStyleFlag { Detailed, Bundled };
-static llvm::cl::opt<CompletionStyleFlag> CompletionStyle(
- "completion-style",
- llvm::cl::desc("Granularity of code completion suggestions"),
- llvm::cl::values(
- clEnumValN(Detailed, "detailed",
- "One completion item for each semantically distinct "
- "completion, with full type information"),
- clEnumValN(Bundled, "bundled",
- "Similar completion items (e.g. function overloads) are "
- "combined. Type information shown where possible")));
+list<std::string> QueryDriverGlobs{
+ "query-driver",
+ cat(CompileCommands),
+ desc(
+ "Comma separated list of globs for white-listing gcc-compatible "
+ "drivers that are safe to execute. Drivers matching any of these globs "
+ "will be used to extract system includes. e.g. "
+ "/usr/bin/**/clang-*,/path/to/repo/**/g++-*"),
+ CommaSeparated,
+};
// FIXME: Flags are the wrong mechanism for user preferences.
// We should probably read a dotfile or similar.
-static llvm::cl::opt<bool> IncludeIneligibleResults(
- "include-ineligible-results",
- llvm::cl::desc(
- "Include ineligible completion results (e.g. private members)"),
- llvm::cl::init(CodeCompleteOptions().IncludeIneligibleResults),
- llvm::cl::Hidden);
-
-static llvm::cl::opt<JSONStreamStyle> InputStyle(
- "input-style", llvm::cl::desc("Input JSON stream encoding"),
- llvm::cl::values(
- clEnumValN(JSONStreamStyle::Standard, "standard", "usual LSP protocol"),
- clEnumValN(JSONStreamStyle::Delimited, "delimited",
- "messages delimited by --- lines, with # comment support")),
- llvm::cl::init(JSONStreamStyle::Standard), llvm::cl::Hidden);
-
-static llvm::cl::opt<bool>
- PrettyPrint("pretty", llvm::cl::desc("Pretty-print JSON output"),
- llvm::cl::init(false));
-
-static llvm::cl::opt<Logger::Level> LogLevel(
- "log", llvm::cl::desc("Verbosity of log messages written to stderr"),
- llvm::cl::values(clEnumValN(Logger::Error, "error", "Error messages only"),
- clEnumValN(Logger::Info, "info",
- "High level execution tracing"),
- clEnumValN(Logger::Debug, "verbose", "Low level details")),
- llvm::cl::init(Logger::Info));
-
-static llvm::cl::opt<bool>
- Test("lit-test",
- llvm::cl::desc("Abbreviation for -input-style=delimited -pretty -sync "
- "-enable-test-scheme -log=verbose."
- "Intended to simplify lit tests"),
- llvm::cl::init(false), llvm::cl::Hidden);
-
-static llvm::cl::opt<bool> EnableTestScheme(
- "enable-test-uri-scheme",
- llvm::cl::desc("Enable 'test:' URI scheme. Only use in lit tests"),
- llvm::cl::init(false), llvm::cl::Hidden);
+opt<bool> AllScopesCompletion{
+ "all-scopes-completion",
+ cat(Features),
+ desc("If set to true, code completion will include index symbols that are "
+ "not defined in the scopes (e.g. "
+ "namespaces) visible from the code completion point. Such completions "
+ "can insert scope qualifiers"),
+ init(true),
+};
-enum PCHStorageFlag { Disk, Memory };
-static llvm::cl::opt<PCHStorageFlag> PCHStorage(
- "pch-storage",
- llvm::cl::desc("Storing PCHs in memory increases memory usages, but may "
- "improve performance"),
- llvm::cl::values(
- clEnumValN(PCHStorageFlag::Disk, "disk", "store PCHs on disk"),
- clEnumValN(PCHStorageFlag::Memory, "memory", "store PCHs in memory")),
- llvm::cl::init(PCHStorageFlag::Disk));
+opt<bool> ShowOrigins{
+ "debug-origin",
+ cat(Features),
+ desc("Show origins of completion items"),
+ init(CodeCompleteOptions().ShowOrigins),
+ Hidden,
+};
-static llvm::cl::opt<int> LimitResults(
- "limit-results",
- llvm::cl::desc("Limit the number of results returned by clangd. "
- "0 means no limit (default=100)"),
- llvm::cl::init(100));
+opt<bool> EnableBackgroundIndex{
+ "background-index",
+ cat(Features),
+ desc("Index project code in the background and persist index on disk. "
+ "Experimental"),
+ init(true),
+};
-static llvm::cl::opt<bool>
- Sync("sync", llvm::cl::desc("Parse on main thread. If set, -j is ignored"),
- llvm::cl::init(false), llvm::cl::Hidden);
+opt<bool> EnableClangTidy{
+ "clang-tidy",
+ cat(Features),
+ desc("Enable clang-tidy diagnostics"),
+ init(true),
+};
-static llvm::cl::opt<Path>
- ResourceDir("resource-dir",
- llvm::cl::desc("Directory for system clang headers"),
- llvm::cl::init(""), llvm::cl::Hidden);
+opt<std::string> ClangTidyChecks{
+ "clang-tidy-checks",
+ cat(Features),
+ desc("List of clang-tidy checks to run (this will override "
+ ".clang-tidy files). Only meaningful when -clang-tidy flag is on"),
+ init(""),
+};
-static llvm::cl::opt<Path> InputMirrorFile(
- "input-mirror-file",
- llvm::cl::desc(
- "Mirror all LSP input to the specified file. Useful for debugging"),
- llvm::cl::init(""), llvm::cl::Hidden);
+opt<CodeCompleteOptions::CodeCompletionParse> CodeCompletionParse{
+ "completion-parse",
+ cat(Features),
+ desc("Whether the clang-parser is used for code-completion"),
+ values(clEnumValN(CodeCompleteOptions::AlwaysParse, "always",
+ "Block until the parser can be used"),
+ clEnumValN(CodeCompleteOptions::ParseIfReady, "auto",
+ "Use text-based completion if the parser "
+ "is not ready"),
+ clEnumValN(CodeCompleteOptions::NeverParse, "never",
+ "Always used text-based completion")),
+ init(CodeCompleteOptions().RunParser),
+ Hidden,
+};
-static llvm::cl::opt<bool> EnableIndex(
- "index",
- llvm::cl::desc(
- "Enable index-based features. By default, clangd maintains an index "
- "built from symbols in opened files. Global index support needs to "
- "enabled separatedly"),
- llvm::cl::init(true), llvm::cl::Hidden);
+// FIXME: also support "plain" style where signatures are always omitted.
+enum CompletionStyleFlag { Detailed, Bundled };
+opt<CompletionStyleFlag> CompletionStyle{
+ "completion-style",
+ cat(Features),
+ desc("Granularity of code completion suggestions"),
+ values(clEnumValN(Detailed, "detailed",
+ "One completion item for each semantically distinct "
+ "completion, with full type information"),
+ clEnumValN(Bundled, "bundled",
+ "Similar completion items (e.g. function overloads) are "
+ "combined. Type information shown where possible")),
+};
-static llvm::cl::opt<bool> AllScopesCompletion(
- "all-scopes-completion",
- llvm::cl::desc(
- "If set to true, code completion will include index symbols that are "
- "not defined in the scopes (e.g. "
- "namespaces) visible from the code completion point. Such completions "
- "can insert scope qualifiers"),
- llvm::cl::init(true));
-
-static llvm::cl::opt<bool> ShowOrigins(
- "debug-origin", llvm::cl::desc("Show origins of completion items"),
- llvm::cl::init(CodeCompleteOptions().ShowOrigins), llvm::cl::Hidden);
-
-static llvm::cl::opt<CodeCompleteOptions::IncludeInsertion> HeaderInsertion(
+opt<std::string> FallbackStyle{
+ "fallback-style",
+ cat(Features),
+ desc("clang-format style to apply by default when "
+ "no .clang-format file is found"),
+ init(clang::format::DefaultFallbackStyle),
+};
+
+opt<bool> EnableFunctionArgSnippets{
+ "function-arg-placeholders",
+ cat(Features),
+ desc("When disabled, completions contain only parentheses for "
+ "function calls. When enabled, completions also contain "
+ "placeholders for method parameters"),
+ init(CodeCompleteOptions().EnableFunctionArgSnippets),
+ Hidden,
+};
+
+opt<CodeCompleteOptions::IncludeInsertion> HeaderInsertion{
"header-insertion",
- llvm::cl::desc("Add #include directives when accepting code completions"),
- llvm::cl::init(CodeCompleteOptions().InsertIncludes),
- llvm::cl::values(
+ cat(Features),
+ desc("Add #include directives when accepting code completions"),
+ init(CodeCompleteOptions().InsertIncludes),
+ values(
clEnumValN(CodeCompleteOptions::IWYU, "iwyu",
"Include what you use. "
"Insert the owning header for top-level symbols, unless the "
@@ -165,118 +202,173 @@ static llvm::cl::opt<CodeCompleteOptions::IncludeInsertion> HeaderInsertion(
"forward-declared"),
clEnumValN(
CodeCompleteOptions::NeverInsert, "never",
- "Never insert #include directives as part of code completion")));
+ "Never insert #include directives as part of code completion")),
+};
-static llvm::cl::opt<bool> HeaderInsertionDecorators(
+opt<bool> HeaderInsertionDecorators{
"header-insertion-decorators",
- llvm::cl::desc("Prepend a circular dot or space before the completion "
- "label, depending on whether "
- "an include line will be inserted or not"),
- llvm::cl::init(true));
+ cat(Features),
+ desc("Prepend a circular dot or space before the completion "
+ "label, depending on whether "
+ "an include line will be inserted or not"),
+ init(true),
+};
+
+opt<bool> HiddenFeatures{
+ "hidden-features",
+ cat(Features),
+ desc("Enable hidden features mostly useful to clangd developers"),
+ init(false),
+ Hidden,
+};
+
+opt<bool> IncludeIneligibleResults{
+ "include-ineligible-results",
+ cat(Features),
+ desc("Include ineligible completion results (e.g. private members)"),
+ init(CodeCompleteOptions().IncludeIneligibleResults),
+ Hidden,
+};
+
+opt<bool> EnableIndex{
+ "index",
+ cat(Features),
+ desc("Enable index-based features. By default, clangd maintains an index "
+ "built from symbols in opened files. Global index support needs to "
+ "enabled separatedly"),
+ init(true),
+ Hidden,
+};
+
+opt<int> LimitResults{
+ "limit-results",
+ cat(Features),
+ desc("Limit the number of results returned by clangd. "
+ "0 means no limit (default=100)"),
+ init(100),
+};
+
+opt<bool> SuggestMissingIncludes{
+ "suggest-missing-includes",
+ cat(Features),
+ desc("Attempts to fix diagnostic errors caused by missing "
+ "includes using index"),
+ init(true),
+};
+
+list<std::string> TweakList{
+ "tweaks",
+ cat(Features),
+ desc("Specify a list of Tweaks to enable (only for clangd developers)."),
+ Hidden,
+ CommaSeparated,
+};
-static llvm::cl::opt<Path> IndexFile(
+opt<unsigned> WorkerThreadsCount{
+ "j",
+ cat(Misc),
+ desc("Number of async workers used by clangd"),
+ init(getDefaultAsyncThreadsCount()),
+};
+
+opt<Path> IndexFile{
"index-file",
- llvm::cl::desc(
+ cat(Misc),
+ desc(
"Index file to build the static index. The file must have been created "
"by a compatible clangd-indexer\n"
"WARNING: This option is experimental only, and will be removed "
"eventually. Don't rely on it"),
- llvm::cl::init(""), llvm::cl::Hidden);
+ init(""),
+ Hidden,
+};
-static llvm::cl::opt<bool> EnableBackgroundIndex(
- "background-index",
- llvm::cl::desc(
- "Index project code in the background and persist index on disk. "
- "Experimental"),
- llvm::cl::init(true));
+opt<bool> Test{
+ "lit-test",
+ cat(Misc),
+ desc("Abbreviation for -input-style=delimited -pretty -sync "
+ "-enable-test-scheme -log=verbose. "
+ "Intended to simplify lit tests"),
+ init(false),
+ Hidden,
+};
-enum CompileArgsFrom { LSPCompileArgs, FilesystemCompileArgs };
-static llvm::cl::opt<CompileArgsFrom> CompileArgsFrom(
- "compile_args_from", llvm::cl::desc("The source of compile commands"),
- llvm::cl::values(clEnumValN(LSPCompileArgs, "lsp",
- "All compile commands come from LSP and "
- "'compile_commands.json' files are ignored"),
- clEnumValN(FilesystemCompileArgs, "filesystem",
- "All compile commands come from the "
- "'compile_commands.json' files")),
- llvm::cl::init(FilesystemCompileArgs), llvm::cl::Hidden);
-
-static llvm::cl::opt<bool> EnableFunctionArgSnippets(
- "function-arg-placeholders",
- llvm::cl::desc("When disabled, completions contain only parentheses for "
- "function calls. When enabled, completions also contain "
- "placeholders for method parameters"),
- llvm::cl::init(CodeCompleteOptions().EnableFunctionArgSnippets),
- llvm::cl::Hidden);
+enum PCHStorageFlag { Disk, Memory };
+opt<PCHStorageFlag> PCHStorage{
+ "pch-storage",
+ cat(Misc),
+ desc("Storing PCHs in memory increases memory usages, but may "
+ "improve performance"),
+ values(
+ clEnumValN(PCHStorageFlag::Disk, "disk", "store PCHs on disk"),
+ clEnumValN(PCHStorageFlag::Memory, "memory", "store PCHs in memory")),
+ init(PCHStorageFlag::Disk),
+};
-static llvm::cl::opt<std::string> ClangTidyChecks(
- "clang-tidy-checks",
- llvm::cl::desc(
- "List of clang-tidy checks to run (this will override "
- ".clang-tidy files). Only meaningful when -clang-tidy flag is on"),
- llvm::cl::init(""));
-
-static llvm::cl::opt<bool>
- EnableClangTidy("clang-tidy",
- llvm::cl::desc("Enable clang-tidy diagnostics"),
- llvm::cl::init(true));
-
-static llvm::cl::opt<std::string>
- FallbackStyle("fallback-style",
- llvm::cl::desc("clang-format style to apply by default when "
- "no .clang-format file is found"),
- llvm::cl::init(clang::format::DefaultFallbackStyle));
-
-static llvm::cl::opt<bool> SuggestMissingIncludes(
- "suggest-missing-includes",
- llvm::cl::desc("Attempts to fix diagnostic errors caused by missing "
- "includes using index"),
- llvm::cl::init(true));
+opt<bool> Sync{
+ "sync",
+ cat(Misc),
+ desc("Parse on main thread. If set, -j is ignored"),
+ init(false),
+ Hidden,
+};
-static llvm::cl::opt<OffsetEncoding> ForceOffsetEncoding(
- "offset-encoding",
- llvm::cl::desc("Force the offsetEncoding used for character positions. "
- "This bypasses negotiation via client capabilities"),
- llvm::cl::values(clEnumValN(OffsetEncoding::UTF8, "utf-8",
- "Offsets are in UTF-8 bytes"),
- clEnumValN(OffsetEncoding::UTF16, "utf-16",
- "Offsets are in UTF-16 code units")),
- llvm::cl::init(OffsetEncoding::UnsupportedEncoding));
-
-static llvm::cl::opt<CodeCompleteOptions::CodeCompletionParse>
- CodeCompletionParse(
- "completion-parse",
- llvm::cl::desc("Whether the clang-parser is used for code-completion"),
- llvm::cl::values(clEnumValN(CodeCompleteOptions::AlwaysParse, "always",
- "Block until the parser can be used"),
- clEnumValN(CodeCompleteOptions::ParseIfReady, "auto",
- "Use text-based completion if the parser "
- "is not ready"),
- clEnumValN(CodeCompleteOptions::NeverParse, "never",
- "Always used text-based completion")),
- llvm::cl::init(CodeCompleteOptions().RunParser), llvm::cl::Hidden);
-
-static llvm::cl::opt<bool> HiddenFeatures(
- "hidden-features",
- llvm::cl::desc("Enable hidden features mostly useful to clangd developers"),
- llvm::cl::init(false), llvm::cl::Hidden);
+opt<JSONStreamStyle> InputStyle{
+ "input-style",
+ cat(Protocol),
+ desc("Input JSON stream encoding"),
+ values(
+ clEnumValN(JSONStreamStyle::Standard, "standard", "usual LSP protocol"),
+ clEnumValN(JSONStreamStyle::Delimited, "delimited",
+ "messages delimited by --- lines, with # comment support")),
+ init(JSONStreamStyle::Standard),
+ Hidden,
+};
-static llvm::cl::list<std::string> QueryDriverGlobs(
- "query-driver",
- llvm::cl::desc(
- "Comma separated list of globs for white-listing gcc-compatible "
- "drivers that are safe to execute. Drivers matching any of these globs "
- "will be used to extract system includes. e.g. "
- "/usr/bin/**/clang-*,/path/to/repo/**/g++-*"),
- llvm::cl::CommaSeparated);
+opt<bool> EnableTestScheme{
+ "enable-test-uri-scheme",
+ cat(Protocol),
+ desc("Enable 'test:' URI scheme. Only use in lit tests"),
+ init(false),
+ Hidden,
+};
-static llvm::cl::list<std::string> TweakList(
- "tweaks",
- llvm::cl::desc(
- "Specify a list of Tweaks to enable (only for clangd developers)."),
- llvm::cl::Hidden, llvm::cl::CommaSeparated);
+opt<Path> InputMirrorFile{
+ "input-mirror-file",
+ cat(Protocol),
+ desc("Mirror all LSP input to the specified file. Useful for debugging"),
+ init(""),
+ Hidden,
+};
-namespace {
+opt<Logger::Level> LogLevel{
+ "log",
+ cat(Protocol),
+ desc("Verbosity of log messages written to stderr"),
+ values(clEnumValN(Logger::Error, "error", "Error messages only"),
+ clEnumValN(Logger::Info, "info", "High level execution tracing"),
+ clEnumValN(Logger::Debug, "verbose", "Low level details")),
+ init(Logger::Info),
+};
+
+opt<OffsetEncoding> ForceOffsetEncoding{
+ "offset-encoding",
+ cat(Protocol),
+ desc("Force the offsetEncoding used for character positions. "
+ "This bypasses negotiation via client capabilities"),
+ values(
+ clEnumValN(OffsetEncoding::UTF8, "utf-8", "Offsets are in UTF-8 bytes"),
+ clEnumValN(OffsetEncoding::UTF16, "utf-16",
+ "Offsets are in UTF-16 code units")),
+ init(OffsetEncoding::UnsupportedEncoding),
+};
+
+opt<bool> PrettyPrint{
+ "pretty",
+ cat(Protocol),
+ desc("Pretty-print JSON output"),
+ init(false),
+};
/// \brief Supports a test URI scheme with relaxed constraints for lit tests.
/// The path in a test URI will be combined with a platform-specific fake
@@ -342,14 +434,19 @@ int main(int argc, char *argv[]) {
llvm::cl::SetVersionPrinter([](llvm::raw_ostream &OS) {
OS << clang::getClangToolFullVersion("clangd") << "\n";
});
- llvm::cl::ParseCommandLineOptions(
- argc, argv,
- "clangd is a language server that provides IDE-like features to editors. "
- "\n\nIt should be used via an editor plugin rather than invoked "
- "directly. "
- "For more information, see:"
- "\n\thttps://clang.llvm.org/extra/clangd.html"
- "\n\thttps://microsoft.github.io/language-server-protocol/");
+ const char *FlagsEnvVar = "CLANGD_FLAGS";
+ const char *Overview =
+ R"(clangd is a language server that provides IDE-like features to editors.
+
+It should be used via an editor plugin rather than invoked directly. For more information, see:
+ https://clang.llvm.org/extra/clangd/
+ https://microsoft.github.io/language-server-protocol/
+
+clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment variable.
+)";
+ llvm::cl::HideUnrelatedOptions(ClangdCategories);
+ llvm::cl::ParseCommandLineOptions(argc, argv, Overview,
+ /*Errs=*/nullptr, FlagsEnvVar);
if (Test) {
Sync = true;
InputStyle = JSONStreamStyle::Delimited;
@@ -414,11 +511,29 @@ int main(int argc, char *argv[]) {
if (Tracer)
TracingSession.emplace(*Tracer);
+ // If a user ran `clangd` in a terminal without redirecting anything,
+ // it's somewhat likely they're confused about how to use clangd.
+ // Show them the help overview, which explains.
+ if (llvm::outs().is_displayed() && llvm::errs().is_displayed())
+ llvm::errs() << Overview << "\n";
// Use buffered stream to stderr (we still flush each log message). Unbuffered
// stream can cause significant (non-deterministic) latency for the logger.
llvm::errs().SetBuffered();
StreamLogger Logger(llvm::errs(), LogLevel);
LoggingSession LoggingSession(Logger);
+ // Write some initial logs before we start doing any real work.
+ log("{0}", clang::getClangToolFullVersion("clangd"));
+ {
+ SmallString<128> CWD;
+ if (auto Err = llvm::sys::fs::current_path(CWD))
+ log("Working directory unknown: {0}", Err.message());
+ else
+ log("Working directory: {0}", CWD);
+ }
+ for (int I = 0; I < argc; ++I)
+ log("argv[{0}]: {1}", I, argv[I]);
+ if (auto EnvFlags = llvm::sys::Process::GetEnv(FlagsEnvVar))
+ log("{0}: {1}", FlagsEnvVar, *EnvFlags);
// If --compile-commands-dir arg was invoked, check value and override default
// path.
@@ -497,12 +612,14 @@ int main(int argc, char *argv[]) {
std::unique_ptr<Transport> TransportLayer;
if (getenv("CLANGD_AS_XPC_SERVICE")) {
#if CLANGD_BUILD_XPC
+ log("Starting LSP over XPC service");
TransportLayer = newXPCTransport();
#else
llvm::errs() << "This clangd binary wasn't built with XPC support.\n";
return (int)ErrorResultCode::CantRunAsXPCService;
#endif
} else {
+ log("Starting LSP over stdin/stdout");
TransportLayer = newJSONTransport(
stdin, llvm::outs(),
InputMirrorStream ? InputMirrorStream.getPointer() : nullptr,