Bash PS1 提示在外部程序生成 ANSI 转义符时换行
Bash PS1 prompt breaks line wrapping when generating ANSI escapes by an external program
我正在考虑使用 C++ 脚本制作自定义 bash 提示符。计划是从 .bash_profile 中的 PS1 声明中调用脚本,如下所示:
PS1='$(bashprompt.out)'
这部分工作得很好。我 运行 遇到的问题是 ANSI 序列被打印到终端。您可以在下图中看到这一点,它过早 returns 到行的开头。
我在格式中定义颜色如下:
#define DGRAYORANGE "3[48;5;202;38;5;243m"
在 bash 脚本中,我知道避免此问题的方法是使用 \[ \]
将颜色表示为非打印(如此处 https://www.funtoo.org/Prompt_Magic) 所述,但在 C++ 中不起作用。
提示应如下所示:
这是用于制作彩色提示的 C++ 代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#include <string>
#include <iostream>
#define ARROW ""
#define DGRAYORANGE "3[48;5;202;38;5;243m"
#define ORANGEDGRAY "3[38;5;202;48;5;243m"
#define DGRAYDEFAULT "3[38;5;243;48;5;0m"
#define WHITEDGRAY "3[38;5;255;48;5;243m"
#define WHITEORANGE "3[38;5;255;48;5;202m"
#define RESET "3[0m"
using namespace std;
void PrintPrompt(string, string, string);
string FormatCWD(char *);
int main() {
int buffersize = 256;
char hostname[buffersize];
char cwd[buffersize];
struct passwd* pw;
gethostname(hostname,sizeof(hostname));
pw = getpwuid(getuid());
getcwd(cwd,sizeof(cwd));
string stringCwd = FormatCWD(cwd);
string stringUsername = pw->pw_name;
string stringHostname = hostname;
PrintPrompt(stringCwd,stringHostname,stringUsername);
}
void PrintPrompt(string cwd, string hostname, string username){
string cwdString = cwd;
cout << WHITEDGRAY << username <<
DGRAYORANGE << ARROW << " " <<
WHITEORANGE << hostname <<
ORANGEDGRAY << ARROW << " " <<
WHITEDGRAY << cwd << DGRAYDEFAULT <<
ARROW << RESET << " " << endl;
}
string FormatCWD(char * cwd) {
string stringCwd = cwd;
int size = stringCwd.length();
int slashCount = 0;
int slashIndex = 0;
for (int i=0; i<size; i++) {
if (stringCwd.at(i) == '/') {
slashIndex = i;
slashCount++;
}
}
string outputCwd = "";
if (slashIndex != 0) {
for (int i=slashIndex+1; i<size; i++) {
outputCwd += stringCwd.at(i);
}
}
return outputCwd;
}
有没有办法通过将转义序列标记为非打印(如 bash)来解决此问题?感谢大家的帮助。
首先请注意 \[
和 \]
由 Bash 本身解释,而不是控制台,因此它们必须明确存在于 PS1
值中,而不是生成实际提示的程序的输出。
现在,您希望计算非转义字符,而不计算颜色。为此,您可以将程序修改为具有两种模式:
- 彩色输出(用于实际提示)
- 纯文本输出(用于字符计数)
然后你可以使用像
这样的东西
PS1='$(/tmp/test)\[\r$(/tmp/test c)\]'
这适用于修改为以下内容的代码:
void PrintPrompt(string cwd, string hostname, string username, bool colors){
string cwdString = cwd;
cout << (colors ? WHITEDGRAY : "") << username <<
(colors ? DGRAYORANGE : "") << ARROW << " " <<
(colors ? WHITEORANGE : "") << hostname <<
(colors ? ORANGEDGRAY : "") << ARROW << " " <<
(colors ? WHITEDGRAY : "") << cwd << (colors ? DGRAYDEFAULT : "") <<
ARROW << (colors ? RESET : "") << endl;
}
with colors
被传递为例如argc>1
.
我们使用 \r
转义序列转到行首,使我们能够用彩色文本覆盖已经打印的非彩色文本,使 Bash 认为额外的文本和转义序列(包括回车 return)不带任何 space.
截图:
我正在考虑使用 C++ 脚本制作自定义 bash 提示符。计划是从 .bash_profile 中的 PS1 声明中调用脚本,如下所示:
PS1='$(bashprompt.out)'
这部分工作得很好。我 运行 遇到的问题是 ANSI 序列被打印到终端。您可以在下图中看到这一点,它过早 returns 到行的开头。
我在格式中定义颜色如下:
#define DGRAYORANGE "3[48;5;202;38;5;243m"
在 bash 脚本中,我知道避免此问题的方法是使用 \[ \]
将颜色表示为非打印(如此处 https://www.funtoo.org/Prompt_Magic) 所述,但在 C++ 中不起作用。
提示应如下所示:
这是用于制作彩色提示的 C++ 代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#include <string>
#include <iostream>
#define ARROW ""
#define DGRAYORANGE "3[48;5;202;38;5;243m"
#define ORANGEDGRAY "3[38;5;202;48;5;243m"
#define DGRAYDEFAULT "3[38;5;243;48;5;0m"
#define WHITEDGRAY "3[38;5;255;48;5;243m"
#define WHITEORANGE "3[38;5;255;48;5;202m"
#define RESET "3[0m"
using namespace std;
void PrintPrompt(string, string, string);
string FormatCWD(char *);
int main() {
int buffersize = 256;
char hostname[buffersize];
char cwd[buffersize];
struct passwd* pw;
gethostname(hostname,sizeof(hostname));
pw = getpwuid(getuid());
getcwd(cwd,sizeof(cwd));
string stringCwd = FormatCWD(cwd);
string stringUsername = pw->pw_name;
string stringHostname = hostname;
PrintPrompt(stringCwd,stringHostname,stringUsername);
}
void PrintPrompt(string cwd, string hostname, string username){
string cwdString = cwd;
cout << WHITEDGRAY << username <<
DGRAYORANGE << ARROW << " " <<
WHITEORANGE << hostname <<
ORANGEDGRAY << ARROW << " " <<
WHITEDGRAY << cwd << DGRAYDEFAULT <<
ARROW << RESET << " " << endl;
}
string FormatCWD(char * cwd) {
string stringCwd = cwd;
int size = stringCwd.length();
int slashCount = 0;
int slashIndex = 0;
for (int i=0; i<size; i++) {
if (stringCwd.at(i) == '/') {
slashIndex = i;
slashCount++;
}
}
string outputCwd = "";
if (slashIndex != 0) {
for (int i=slashIndex+1; i<size; i++) {
outputCwd += stringCwd.at(i);
}
}
return outputCwd;
}
有没有办法通过将转义序列标记为非打印(如 bash)来解决此问题?感谢大家的帮助。
首先请注意 \[
和 \]
由 Bash 本身解释,而不是控制台,因此它们必须明确存在于 PS1
值中,而不是生成实际提示的程序的输出。
现在,您希望计算非转义字符,而不计算颜色。为此,您可以将程序修改为具有两种模式:
- 彩色输出(用于实际提示)
- 纯文本输出(用于字符计数)
然后你可以使用像
这样的东西PS1='$(/tmp/test)\[\r$(/tmp/test c)\]'
这适用于修改为以下内容的代码:
void PrintPrompt(string cwd, string hostname, string username, bool colors){
string cwdString = cwd;
cout << (colors ? WHITEDGRAY : "") << username <<
(colors ? DGRAYORANGE : "") << ARROW << " " <<
(colors ? WHITEORANGE : "") << hostname <<
(colors ? ORANGEDGRAY : "") << ARROW << " " <<
(colors ? WHITEDGRAY : "") << cwd << (colors ? DGRAYDEFAULT : "") <<
ARROW << (colors ? RESET : "") << endl;
}
with colors
被传递为例如argc>1
.
我们使用 \r
转义序列转到行首,使我们能够用彩色文本覆盖已经打印的非彩色文本,使 Bash 认为额外的文本和转义序列(包括回车 return)不带任何 space.
截图: