我开始用 C 语言(在 Windows 上)为我的语言编写 vscode 的 LSP 扩展。当作为子进程生成时,我无法让极其简单的 C 程序刷新标准输出(vscode 就是这样做的)。当我直接从命令行运行相同的程序时,它按预期工作。我有一个简单的 python 脚本来模拟 lsp 协议,我在这里看到的行为与在 vscode 下运行时的行为相同。
这是我可以用来模拟错误的最简单的 C 程序。 (我有一个 C++ 程序,它与
std::cout
和朋友的行为方式相同)
#include <windows.h>
#include <stdio.h>
int main() {
char buffer[1024];
// Infinite loop to continuously listen for LSP requests
// without the loop it works fine.
while (1) {
if (fgets(buffer, 1024, stdin) == NULL) {
break;
}
const char* contentOffset = buffer + 16; // read content value (16 is the size of "Content-Length:"
char* pEnd;
size_t len = strtoll(contentOffset, &pEnd, 10) + 1;
fgets(buffer, 1024, stdin); // read empty line
// Read the JSON body based on Content-Length
fgets(buffer, (int32) len, stdin);
// Process the incoming JSON body (simple echo back for testing)
// Echo the same JSON body back with the appropriate LSP header
printf("Content-Length: %d\r\n\r\n%s", (int32_t)len - 1, buffer); // I've also tried fprintf and the windows apis as well, same effect
// Flush stdout to ensure the message is sent immediately (this seems to have no effect)
fflush(stdout);
}
return 0;
}
这是一个简单的Python脚本来模拟lsp
import subprocess
import time
# Start the C program
process = subprocess.Popen(
["path/to/exe"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True, # Ensure text mode
)
# Function to send LSP request and read response
def send_lsp_request(json_request):
content_length = len(json_request)
# Send the LSP-style request
lsp_message = f"Content-Length: {content_length}\r\n\r\n{json_request}"
process.stdin.write(lsp_message)
process.stdin.flush()
# Allow some time for the C program to respond
time.sleep(0.1)
# Read and print the response from stdout
response = process.stdout.read(1024)
return response
# Example LSP request
json_request = '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {}}'
print('sent')
# Send a request to the C LSP server and print the response
response = send_lsp_request(json_request)
print("Response from C program:\n", response)
我希望程序在这两种情况下表现相同。相反,当使用 python 脚本运行时,它会打印
sent
,然后永远挂起,等待进程将某些内容放入 stdout
,但这种情况永远不会发生。
如果我删除 C 程序中的
while
循环,我们会得到我们期望的输出,但我实际上无法做到这一点,因为程序需要继续侦听更多消息。
我不知道为什么会发生这种情况。我读过一些关于继承句柄的内容,但我无法控制 vscode 对此的处理方式,如果 vscode 提供的 stdio 传输没有为此做正确的事情,我会感到惊讶。我没有其他硬件来判断这是否是 Windows 独有的问题。
任何见解都令人难以置信。
process.stdout.read(1024)
显然等待 1024 字节(或 EOF)。我找不到它的文档,但我可以演示它:
$ perl -Mv5.14 -e'say "hi"; sleep( 3 );' | cat
<3 second pause due to lack of flushing>
hi
$ perl -Mv5.14 -e'say "hi"; STDOUT->flush; sleep( 3 );' | cat
hi
<3 second pause>
$ perl -Mv5.14 -e'say "hi"; STDOUT->flush; sleep( 3 );' |
python3 -c 'import sys; print(sys.stdin.read(10), end="");'
<3 second pause>
hi
抱歉,我不太了解 Python,无法提供解决方案。