Skip to content

Commit 2f66c24

Browse files
committed
Support reading file from standard input
Fixes quick-lint#263 Updates quick-lint#275 Signed-off-by: wagner riffel <[email protected]>
1 parent dac5b6a commit 2f66c24

File tree

6 files changed

+52
-1
lines changed

6 files changed

+52
-1
lines changed

src/file.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,11 @@ read_file_result read_file(const char *path) {
211211
windows_handle_file file(handle);
212212
return read_file(path, file.ref());
213213
}
214+
215+
read_file_result read_stdin() {
216+
windows_handle_file file(::GetStdHandle(STD_INPUT_HANDLE));
217+
return read_file("<stdin>", file.ref());
218+
}
214219
#endif
215220

216221
#if defined(QLJS_FILE_POSIX)
@@ -224,6 +229,11 @@ read_file_result read_file(const char *path) {
224229
posix_fd_file file(fd);
225230
return read_file(path, file.ref());
226231
}
232+
233+
read_file_result read_stdin() {
234+
posix_fd_file file(STDIN_FILENO);
235+
return read_file("<stdin>", file.ref());
236+
}
227237
#endif
228238

229239
void write_file(const std::string &path, string8_view content) {

src/main.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,20 @@ void handle_options(quick_lint_js::options o) {
150150
quick_lint_js::run_lsp_server();
151151
std::exit(EXIT_SUCCESS);
152152
}
153-
if (o.files_to_lint.empty()) {
153+
if (o.files_to_lint.empty() && !o.stdin) {
154154
std::cerr << "error: expected file name\n";
155155
std::exit(EXIT_FAILURE);
156156
}
157157

158158
quick_lint_js::any_error_reporter reporter =
159159
quick_lint_js::any_error_reporter::make(o.output_format, &o.exit_fail_on);
160+
if (o.stdin) {
161+
quick_lint_js::read_file_result source = quick_lint_js::read_stdin();
162+
file_to_lint fstdin{.path = "<stdin>", .vim_bufnr = std::nullopt};
163+
reporter.set_source(&source.content, fstdin);
164+
quick_lint_js::process_file(&source.content, reporter.get(),
165+
o.print_parser_visits);
166+
}
160167
for (const quick_lint_js::file_to_lint &file : o.files_to_lint) {
161168
quick_lint_js::read_file_result source =
162169
quick_lint_js::read_file(file.path);
@@ -394,6 +401,7 @@ void print_help_message() {
394401
print_option("--exit-fail-on=[CODES]",
395402
"Fail with a non-zero exit code if any of these");
396403
print_option("", "errors are found (default: \"all\")");
404+
print_option("--s, --stdin", "Read standard input as a javascript file");
397405
print_option("--lsp, --lsp-server",
398406
"Run in Language Server mode (for LSP-aware editors)");
399407
print_option("--output-format=[FORMAT]",

src/options.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ class arg_parser {
9999
this->is_ignoring_options_ = true;
100100
this->option_ = std::nullopt;
101101
} else if (this->current_arg()[0] == '-') {
102+
if (std::strcmp(this->current_arg(), "-") == 0) {
103+
this->option_ = std::nullopt;
104+
return;
105+
}
102106
const char* equal = std::strchr(this->current_arg(), '=');
103107
option o;
104108
o.arg_has_equal = equal != nullptr;
@@ -152,6 +156,10 @@ options parse_options(int argc, char** argv) {
152156
arg_parser parser(argc, argv);
153157
while (!parser.done()) {
154158
if (const char* argument = parser.match_argument()) {
159+
if (std::strcmp(argument, "-") == 0) {
160+
o.stdin = true;
161+
continue;
162+
}
155163
file_to_lint file{.path = argument, .vim_bufnr = next_vim_file_bufnr};
156164
o.files_to_lint.emplace_back(file);
157165
next_vim_file_bufnr = std::nullopt;
@@ -188,6 +196,8 @@ options parse_options(int argc, char** argv) {
188196
o.version = true;
189197
} else if (parser.match_flag_option("--lsp-server"sv, "--lsp"sv)) {
190198
o.lsp_server = true;
199+
} else if (parser.match_flag_option("--stdin"sv, "--s"sv)) {
200+
o.stdin = true;
191201
} else {
192202
const char* unrecognized = parser.match_anything();
193203
o.error_unrecognized_options.emplace_back(unrecognized);

src/quick-lint-js/file.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ read_file_result read_file(const char *path);
2424

2525
read_file_result read_file(const char *path, platform_file_ref);
2626

27+
read_file_result read_stdin(void);
28+
2729
void write_file(const std::string &path, string8_view content);
2830
void write_file(const char *path, string8_view content);
2931
}

src/quick-lint-js/options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct options {
2626
bool version = false;
2727
bool print_parser_visits = false;
2828
bool lsp_server = false;
29+
bool stdin = false;
2930
quick_lint_js::output_format output_format =
3031
quick_lint_js::output_format::default_format;
3132
std::vector<file_to_lint> files_to_lint;

test/test-options.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ TEST(test_options, default_options_with_no_files) {
3535
EXPECT_FALSE(o.help);
3636
EXPECT_FALSE(o.version);
3737
EXPECT_FALSE(o.lsp_server);
38+
EXPECT_FALSE(o.stdin);
3839
EXPECT_EQ(o.output_format, output_format::default_format);
3940
EXPECT_THAT(o.files_to_lint, IsEmpty());
4041
}
@@ -176,6 +177,25 @@ TEST(test_options, lsp_server) {
176177
}
177178
}
178179

180+
TEST(test_options, stdin) {
181+
{
182+
options o = parse_options({"--stdin"});
183+
EXPECT_TRUE(o.stdin);
184+
}
185+
{
186+
options o = parse_options({"--s"});
187+
EXPECT_TRUE(o.stdin);
188+
}
189+
}
190+
191+
TEST(test_options, single_hypen_is_argument) {
192+
{
193+
options o = parse_options({"one.js", "-", "two.js"});
194+
ASSERT_EQ(o.files_to_lint.size(), 2);
195+
EXPECT_TRUE(o.stdin);
196+
}
197+
}
198+
179199
TEST(test_options, print_help) {
180200
{
181201
options o = parse_options({"--help"});

0 commit comments

Comments
 (0)