Open DehanLUO opened 4 days ago
Now that the principle is clear, I can verify the slave-side buffer size of a local pseudo-terminal, which is limited to 1024 characters, through both code and direct terminal operations.
#include <iostream>
#include <unistd.h>
#include <util.h> // macOS-specific header for openpty
constexpr int kTestSize = 2048; // Test size exceeds assumed buffer size of 1024
int main() {
int master_fd, slave_fd;
// Open a pseudo-terminal pair
if (openpty(&master_fd, &slave_fd, nullptr, nullptr, nullptr) == -1) {
perror("openpty");
return 1;
}
char write_buffer[kTestSize];
char read_buffer[kTestSize];
memset(write_buffer, 'A', sizeof(write_buffer)); // Fill buffer with 'A'
// Write data to master end
ssize_t bytes_written = write(master_fd, write_buffer, sizeof(write_buffer));
if (bytes_written == -1) {
perror("write");
return 1;
}
// Read data from master end
ssize_t bytes_read = read(master_fd, read_buffer, sizeof(read_buffer));
if (bytes_read == -1) {
perror("read");
return 1;
}
std::cout << "Bytes written: " << bytes_written << ", Bytes read: " << bytes_read << std::endl;
close(master_fd);
close(slave_fd);
return 0;
}
On my macOS system, this C++ code produces the following output:
Bytes written: 2048, Bytes read: 1024
Pre-copy a text string longer than 1024 characters. With the .zshrc configuration mentioned earlier, while sleep is blocking, paste the text into the Terminal. We can observe that only 1024 characters are pasted, and the excess is truncated. Once the shell resumes, only 1024 characters are consumed from the buffer.
Thanks for all of the info. Looks like we'd need to investigate what happens here
For a long time, my Visual Studio Code setup, along with its extensions, functioned flawlessly and significantly improved my workflow. However, at some point, I began experiencing issues with certain extensions. Notably, when debugging C++ code with CodeLLDB or CMake Tools, the commands sent to the terminal would occasionally be truncated, preventing the debugger from launching properly.
Recently, I discovered that setting
"terminal.integrated.defaultProfile.osx": "bash"
resolved the issue, while switching back to zsh caused it to resurface. Later, after transferring some conda and jenv initialization settings from.zshrc
to.bash_profile
, I found that the problem began to intermittently occur in bash as well. Interestingly, the more configuration scripts I added, the more consistently the issue appeared.Recognizing a pattern, I decided to investigate further by reviewing discussions and documentation in the project’s GitHub repository.
Historical Discussions
An issue similar to what I am currently experiencing was first raised back in 2017 as #38137. Although it did not provide a direct solution to my problem and was eventually closed because it could not be reproduced, I would like to acknowledge @Tyriar for his extensive contributions in that discussion, where he referenced several related issues that offered valuable insights.
One notable comment came from @fabiospampinato, who mentioned that the command truncation only happens the first time text is sent to the terminal, but works properly afterwards.
The character limit at which commands are truncated seems to vary across different operating systems. According to #63613, commands exceeding 1568 characters are truncated on Windows. Meanwhile, issues such as #59135, #87183, #130736, and #134324 indicate that on macOS, this limit is 1024 characters, which aligns with my observations.
Additionally, issues #96973 and #61999 provided effective testing methods for the "Run selected text in active terminal" functionality. Additionally, #136587 offered an approach for testing using
launch.json
, which significantly simplified my process of reproducing this issue.I also found the enable trace logging guide in the project’s wiki, which helped me expedite the process of identifying the cause of the problem.
Steps to Reproduce
Modify
~/.zshrc
. The configurations foroh-my-zsh
,jenv
, andconda
can introduce delays during zsh initialization. To simulate this, add asleep
command with timestamps for tracking:Configure
settings.json
. Set the terminal settings to use zsh and disable environment inheritance:Set Log Level to Trace.
Verify that all Terminal instances are closed to ensure the next session undergoes full
.zshrc
initialization.Create a text file containing a single line exceeding 1024 characters. Below is an example, where the space after
256
marks the 1024-character boundary:Select the entire text and use Terminal: Run Selected Text in Active Terminal. Observe that commands beyond 1024 characters, starting from
257
, are truncated.Examine the logs for details on the truncation and potential causes.
Cross-referencing the code and logs
In the ptyhost.log, I observed the following two log entries. The line:
is the last time the text I entered appeared in full. This log entry was generated by this._logService.trace('node-pty.IPty#write', object.data);. At this point, the input remains intact. The data is then passed through this._ptyProcess!.write(object.data); into the
node-pty
module, where it is further processed by this._socket.write(data);. This method facilitates communication with the C++ layer, which writes the data to the master side of the pseudo-terminal created via int ret = openpty(&master, &slave, nullptr, NULL, static_cast<winsize*>(&winp));.The line:
marks the first instance of text truncation. In the { return this._onData.event; } event, allowing subscribed listeners to capture the incoming data. In
node-pty
project, when the master side of the pseudo-terminal receives data, it triggers the public get onData(): IEventvscode
, theonData
event is subscribed to, and the captured data is logged via this._logService.trace('node-pty.IPty#onData', data);.Notably, I observed two occurrences of the
gdate
timestamp output from.zshrc
in theonData
logs:Additionally, after the shell finished loading
.zshrc
, there was another instance of truncated output:Since the pseudo-terminal’s slave side in the
node-pty
project is configured withECHO
mode enabled (term->c_lflag = ICANON | ISIG | IEXTEN | ECHO | ECHOE | ECHOK | ECHOKE | ECHOCTL;
), the echo back at2024-11-06 22:28:02.211
corresponds to the data being written to the slave's buffer by the master. At this point, the shell on the slave side is still initializing.zshrc
and has not consumed any data from the buffer.Once the shell finishes initialization and begins consuming data from the slave's buffer, this data is echoed back to the slave and subsequently captured by the master, triggering the corresponding
onData
events.Conclusion
In summary, on my macOS system, the issue of commands exceeding 1024 characters being truncated in the terminal stems from how Visual Studio Code interacts with the pseudo-terminal via
node-pty
. During shell initialization, which involves blocking processes, VSCode continues to write data to the slave side of the pseudo-terminal. Once the buffer reaches its maximum capacity, any additional data is discarded. When the shell resumes, it can only read as much data as fits within the buffer's limit, resulting in truncated commands.