mirror of
https://github.com/neovim/neovim.git
synced 2025-12-07 07:02:46 +00:00
Problem:
Neovim no longer ships with a tee binary on Windows, which breaks
functionality for the :grep and :make commands.
nvim --clean
:grep foo or :make
"tee is not recognized as an internal or external command"
Solution:
Include a simple, no-dependency tee.c source file in the src/ directory.
Update CMakeLists.txt to build a tee executable alongside neovim during
the build process, and ensure the tee.exe program appears alongside the
neovim executable in the bin/ directory so that it is accessible for
:grep and :make.
tee.c was obtained from the vim codebase:
https://github.com/vim/vim/blob/master/src/tee/tee.c
And we modified it to fix performance issues.
Testing:
nvim --clean
:grep foo or :make, after setting a file to the makeprg option.
Verify that :grep results and error output from a compiler appear in the message pane.
ref https://github.com/neovim/neovim/issues/32431
fix https://github.com/neovim/neovim/issues/32504
Other tee options:
- [tee-win32](https://github.com/dEajL3kA/tee-win32): MIT. However,
I couldn't get it to build on my machine even after updating its
makefile to call my install of MSVC. It's also super optimized and
uses some processor intrinsics for multithreading.
- [gnu coreutils tee](https://gnuwin32.sourceforge.net/packages/coreutils.htm):
(Windows coreutils contains a tee.c. Last updated 2005. Did not build
immediately on my machine; we'd have to determine which definitions
from elsewhere in coreutils tee.c needs and incorporate them somehow.
- [WinTee](https://github.com/mpderbec/WinTee): Has no license. Last
updated 11 years ago. Relies on Visual Studio to build.
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
131 lines
3.6 KiB
C
131 lines
3.6 KiB
C
// tee.c - pipe fitting
|
|
//
|
|
// Copyright (c) 1996, Paul Slootman
|
|
//
|
|
// Author: Paul Slootman
|
|
// (paul@wurtel.hobby.nl, paul@murphy.nl, paulS@toecompst.nl)
|
|
// Modifications for MSVC: Yasuhiro Matsumoto
|
|
// Modifications for Neovim: https://github.com/neovim/neovim/pull/36363
|
|
//
|
|
// This source code is released into the public domain. It is provided on an
|
|
// as-is basis and no responsibility is accepted for its failure to perform
|
|
// as expected. It is worth at least as much as you paid for it!
|
|
//
|
|
//
|
|
// tee reads stdin, and writes what it reads to each of the specified
|
|
// files. The primary reason of existence for this version is a quick
|
|
// and dirty implementation to distribute with Vim, to make one of the
|
|
// most useful features of Vim possible on OS/2: quickfix.
|
|
//
|
|
// Of course, not using tee but instead redirecting make's output directly
|
|
// into a temp file and then processing that is possible, but if we have a
|
|
// system capable of correctly piping (unlike DOS, for example), why not
|
|
// use it as well as possible? This tee should also work on other systems,
|
|
// but it's not been tested there, only on OS/2.
|
|
//
|
|
// tee is also available in the GNU shellutils package, which is available
|
|
// precompiled for OS/2. That one probably works better.
|
|
|
|
#ifndef _MSC_VER
|
|
# include <unistd.h>
|
|
#endif
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifdef _WIN32
|
|
# define sysconf(x) - 1
|
|
#endif
|
|
|
|
void usage(void)
|
|
{
|
|
fprintf(stderr,
|
|
"Neotee: a web-scale fork of tee\n"
|
|
"Usage:\n"
|
|
"\ttee [-a] file ... file_n\n"
|
|
"\n"
|
|
"\t-a\tappend to files instead of truncating\n"
|
|
"\n"
|
|
"Tee reads its input, and writes to each of the specified files,\n"
|
|
"as well as to the standard output.\n"
|
|
"\n"
|
|
"Shipped with Nvim 0.12+ for use with :make, :grep, :!, etc.\n");
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int append = 0;
|
|
size_t numfiles;
|
|
int maxfiles;
|
|
FILE **filepointers;
|
|
int i;
|
|
char buf[65536];
|
|
int n;
|
|
int optnr = 1;
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
if (argv[i][0] != '-') {
|
|
break;
|
|
}
|
|
if (!strcmp(argv[i], "-a")) {
|
|
append++;
|
|
} else {
|
|
usage();
|
|
exit(2);
|
|
}
|
|
optnr++;
|
|
}
|
|
|
|
numfiles = argc - optnr;
|
|
|
|
if (numfiles == 0) {
|
|
usage();
|
|
exit(2);
|
|
}
|
|
|
|
maxfiles = sysconf(_SC_OPEN_MAX); // or fill in 10 or so
|
|
if (maxfiles < 0) {
|
|
maxfiles = 10;
|
|
}
|
|
if (numfiles + 3 > maxfiles) { // +3 accounts for stdin, out, err
|
|
fprintf(stderr, "There is a limit of max %d files.\n", maxfiles - 3);
|
|
exit(1);
|
|
}
|
|
filepointers = calloc(numfiles, sizeof(FILE *)); // NOLINT
|
|
if (filepointers == NULL) {
|
|
fprintf(stderr, "Error allocating memory for %ld files\n", (long)numfiles);
|
|
exit(1);
|
|
}
|
|
for (i = 0; i < numfiles; i++) {
|
|
filepointers[i] = fopen(argv[i + optnr], append ? "ab" : "wb");
|
|
if (filepointers[i] == NULL) {
|
|
fprintf(stderr, "Can't open \"%s\"\n", argv[i + optnr]);
|
|
exit(1);
|
|
}
|
|
}
|
|
#ifdef _WIN32
|
|
setmode(fileno(stdin), O_BINARY);
|
|
fflush(stdout); // needed for _fsetmode(stdout)
|
|
setmode(fileno(stdout), O_BINARY);
|
|
setvbuf(stdout, NULL, _IONBF, 0); // unbuffered for immediate output
|
|
#endif
|
|
|
|
while ((n = fread(buf, 1, sizeof(buf), stdin)) > 0) {
|
|
fwrite(buf, 1, n, stdout);
|
|
for (i = 0; i < numfiles; i++) {
|
|
if (filepointers[i]) {
|
|
fwrite(buf, 1, n, filepointers[i]);
|
|
}
|
|
}
|
|
fflush(stdout);
|
|
}
|
|
for (i = 0; i < numfiles; i++) {
|
|
if (filepointers[i]) {
|
|
fclose(filepointers[i]);
|
|
}
|
|
}
|
|
|
|
exit(0);
|
|
}
|