diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 36b42e28e3..e83fc25f88 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -409,6 +409,8 @@ The following changes to existing APIs or features add new behavior. • |nvim_open_win()| and |nvim_win_set_config()| now support opening normal (split) windows, and moving floating windows into split windows. +• 'errorfile' (|-q|) accepts `-` as an alias for stdin. + ============================================================================== REMOVED FEATURES *news-removed* diff --git a/src/nvim/main.c b/src/nvim/main.c index 6d71dc618a..f858313682 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1016,6 +1016,7 @@ static bool edit_stdin(mparm_T *parmp) && !(embedded_mode && stdin_fd <= 0) && (!exmode_active || parmp->input_istext) && !stdin_isatty + && parmp->edit_type <= EDIT_STDIN && parmp->scriptin == NULL; // `-s -` was not given. return parmp->had_stdin_file || implicit; } diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index 0141db7553..d24681a156 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -25,10 +25,6 @@ #include "nvim/rbuffer_defs.h" #include "nvim/types_defs.h" -#ifdef MSWIN -# include "nvim/os/os_win_console.h" -#endif - #ifdef HAVE_SYS_UIO_H # include #endif @@ -179,17 +175,7 @@ FileDescriptor *file_open_stdin(void) FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT { int error; - int stdin_dup_fd; - if (stdin_fd > 0) { - stdin_dup_fd = stdin_fd; - } else { - stdin_dup_fd = os_dup(STDIN_FILENO); -#ifdef MSWIN - // Replace the original stdin with the console input handle. - os_replace_stdin_to_conin(); -#endif - } - FileDescriptor *const stdin_dup = file_open_fd_new(&error, stdin_dup_fd, + FileDescriptor *const stdin_dup = file_open_fd_new(&error, os_open_stdin_fd(), kFileReadOnly|kFileNonBlocking); assert(stdin_dup != NULL); if (error != 0) { diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index d80539708d..566d51f30a 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -55,6 +55,7 @@ #ifdef MSWIN # include "nvim/mbyte.h" # include "nvim/option.h" +# include "nvim/os/os_win_console.h" # include "nvim/strings.h" #endif @@ -541,6 +542,22 @@ os_dup_dup: return ret; } +/// Open the file descriptor for stdin. +int os_open_stdin_fd(void) +{ + int stdin_dup_fd; + if (stdin_fd > 0) { + stdin_dup_fd = stdin_fd; + } else { + stdin_dup_fd = os_dup(STDIN_FILENO); +#ifdef MSWIN + // Replace the original stdin with the console input handle. + os_replace_stdin_to_conin(); +#endif + } + return stdin_dup_fd; +} + /// Read from a file /// /// Handles EINTR and ENOMEM, but not other errors. diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 801c00933a..14758c8cea 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -1065,7 +1065,9 @@ static int qf_setup_state(qfstate_T *pstate, char *restrict enc, const char *res } if (efile != NULL - && (pstate->fd = os_fopen(efile, "r")) == NULL) { + && (pstate->fd = (strequal(efile, "-") + ? fdopen(os_open_stdin_fd(), "r") + : os_fopen(efile, "r"))) == NULL) { semsg(_(e_openerrf), efile); return FAIL; } diff --git a/test/functional/ui/embed_spec.lua b/test/functional/ui/embed_spec.lua index f6bdd2215d..0445476780 100644 --- a/test/functional/ui/embed_spec.lua +++ b/test/functional/ui/embed_spec.lua @@ -3,6 +3,7 @@ local uv = vim.uv local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') +local api = helpers.api local feed = helpers.feed local eq = helpers.eq local neq = helpers.neq @@ -11,6 +12,7 @@ local ok = helpers.ok local fn = helpers.fn local nvim_prog = helpers.nvim_prog local retry = helpers.retry +local write_file = helpers.write_file local function test_embed(ext_linegrid) local screen @@ -113,26 +115,83 @@ describe('--embed UI', function() writer:close() end) - screen:expect { - grid = [[ + screen:expect [[ ^hello nvim | from external input | {1:~ }|*5 | - ]], - } + ]] -- stdin (rpc input) still works feed 'o' - screen:expect { - grid = [[ + screen:expect [[ hello nvim | ^ | from external input | {1:~ }|*4 {2:-- INSERT --} | - ]], + ]] + end) + + it('can pass stdin to -q - #17523', function() + write_file( + 'Xbadfile.c', + [[ + /* some file with an error */ + main() { + functionCall(arg; arg, arg); + return 666 + } + ]] + ) + finally(function() + os.remove('Xbadfile.c') + end) + + local pipe = assert(uv.pipe()) + + local writer = assert(uv.new_pipe(false)) + writer:open(pipe.write) + + clear { args_rm = { '--headless' }, args = { '-q', '-' }, io_extra = pipe.read } + + -- attach immediately after startup, for early UI + local screen = Screen.new(60, 8) + screen.rpc_async = true -- Avoid hanging. #24888 + screen:attach { stdin_fd = 3 } + screen:set_default_attr_ids { + [1] = { bold = true, foreground = Screen.colors.Blue1 }, + [2] = { bold = true }, } + + writer:write [[Xbadfile.c:4:12: error: expected ';' before '}' token]] + writer:shutdown(function() + writer:close() + end) + + screen:expect [[ + /* some file with an error */ | + main() { | + functionCall(arg; arg, arg); | + return 66^6 | + } | + {1:~ }|*2 + (1 of 1): error: expected ';' before '}' token | + ]] + + -- stdin (rpc input) still works + feed 'A' + screen:expect [[ + /* some file with an error */ | + main() { | + functionCall(arg; arg, arg); | + return 666^ | + } | + {1:~ }|*2 + {2:-- INSERT --} | + ]] + + eq('-', api.nvim_get_option_value('errorfile', {})) end) it('only sets background colors once even if overridden', function()