able to navigate by left and right arrow keys, and insert in middle of command
This commit is contained in:
parent
460105a7ba
commit
0174f877ee
1 changed files with 99 additions and 24 deletions
123
rush.c
123
rush.c
|
@ -32,7 +32,6 @@ void change_terminal_attribute(int option) {
|
||||||
char **setup_path_variable() {
|
char **setup_path_variable() {
|
||||||
char *envpath = getenv("PATH");
|
char *envpath = getenv("PATH");
|
||||||
if (envpath == NULL) {
|
if (envpath == NULL) {
|
||||||
// ?????
|
|
||||||
fprintf(stderr, "rush: PATH environment variable is missing\n");
|
fprintf(stderr, "rush: PATH environment variable is missing\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
@ -75,6 +74,7 @@ bool find_command(char **paths, char *command) {
|
||||||
}
|
}
|
||||||
while (*paths != NULL) {
|
while (*paths != NULL) {
|
||||||
char current_path[PATH_MAX];
|
char current_path[PATH_MAX];
|
||||||
|
current_path[0] = '\0';
|
||||||
sprintf(current_path, "%s/%s", *paths, command);
|
sprintf(current_path, "%s/%s", *paths, command);
|
||||||
if (access(current_path, X_OK) == 0) {
|
if (access(current_path, X_OK) == 0) {
|
||||||
// command is executable
|
// command is executable
|
||||||
|
@ -89,12 +89,23 @@ bool find_command(char **paths, char *command) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void shiftleft(int chars) {
|
||||||
|
printf("\033[%dD", chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
void shiftright(int chars) {
|
||||||
|
printf("\033[%dC", chars);
|
||||||
|
}
|
||||||
|
|
||||||
char *readline(char **paths) {
|
char *readline(char **paths) {
|
||||||
int bufsize = RL_BUFSIZE;
|
int bufsize = RL_BUFSIZE;
|
||||||
int position = 0;
|
int position = 0;
|
||||||
char *buffer = malloc(sizeof(char) * bufsize);
|
char *buffer = malloc(sizeof(char) * bufsize);
|
||||||
int c;
|
|
||||||
|
|
||||||
|
bool moved = false;
|
||||||
|
bool backspaced = false;
|
||||||
|
bool navigated = false;
|
||||||
|
bool insertatmiddle = false;
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
fprintf(stderr, "rush: Error allocating memory\n");
|
fprintf(stderr, "rush: Error allocating memory\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
@ -102,17 +113,15 @@ char *readline(char **paths) {
|
||||||
|
|
||||||
buffer[0] = '\0';
|
buffer[0] = '\0';
|
||||||
while (1) {
|
while (1) {
|
||||||
c = getchar(); // read a character
|
int c = getchar(); // read a character
|
||||||
int buf_len = strlen(buffer);
|
int buf_len = strlen(buffer);
|
||||||
if (buf_len > 0) {
|
|
||||||
printf("\033[%ldD", strlen(buffer)); // move cursor to the beginning
|
|
||||||
printf("\033[K"); // clear line to the right of cursor
|
|
||||||
}
|
|
||||||
// check each character user has input
|
// check each character user has input
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case EOF:
|
case EOF:
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
case 10: // enter/new line feed
|
case 10: {
|
||||||
|
// enter/new line feed
|
||||||
if (buf_len == 0) {
|
if (buf_len == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -121,12 +130,20 @@ char *readline(char **paths) {
|
||||||
for (int start = buf_len + 1; buffer[start] != '\0'; start++) {
|
for (int start = buf_len + 1; buffer[start] != '\0'; start++) {
|
||||||
buffer[start] = '\0';
|
buffer[start] = '\0';
|
||||||
}
|
}
|
||||||
printf("%s\n", buffer); // print back the command in prompt
|
printf("\n"); // give space for response
|
||||||
save_command_history(buffer);
|
save_command_history(buffer);
|
||||||
|
position = 0;
|
||||||
return buffer;
|
return buffer;
|
||||||
|
}
|
||||||
case 127: // backspace
|
case 127: // backspace
|
||||||
if (buf_len >= 1) {
|
if (buf_len >= 1) {
|
||||||
buffer[buf_len - 1] = '\0'; // putting null character at last character to act as backspace
|
position--;
|
||||||
|
for (int i = position; i < buf_len; i++) {
|
||||||
|
// shift the buffer
|
||||||
|
buffer[i] = buffer[i + 1];
|
||||||
|
}
|
||||||
|
backspaced = true;
|
||||||
|
moved = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 27: // arrow keys comes at three characters, 27, 91, then 65-68
|
case 27: // arrow keys comes at three characters, 27, 91, then 65-68
|
||||||
|
@ -137,45 +154,90 @@ char *readline(char **paths) {
|
||||||
char *last_command = read_command(1);
|
char *last_command = read_command(1);
|
||||||
if (last_command != NULL) {
|
if (last_command != NULL) {
|
||||||
strcpy(buffer, last_command);
|
strcpy(buffer, last_command);
|
||||||
buf_len = strlen(buffer) - 1;
|
navigated = true;
|
||||||
}
|
}
|
||||||
|
moved = false;
|
||||||
break;
|
break;
|
||||||
} else if (arrow_key == 66) { // down
|
} else if (arrow_key == 66) { // down
|
||||||
char *last_command = read_command(0);
|
char *last_command = read_command(0);
|
||||||
if (last_command != NULL) {
|
if (last_command != NULL) {
|
||||||
strcpy(buffer, last_command);
|
strcpy(buffer, last_command);
|
||||||
buf_len = strlen(buffer) - 1;
|
navigated = true;
|
||||||
}
|
}
|
||||||
|
moved = false;
|
||||||
break;
|
break;
|
||||||
} else if (arrow_key == 67) { // right
|
} else if (arrow_key == 67) { // right
|
||||||
if (position < buf_len) {
|
if (position < buf_len) {
|
||||||
printf("\033[%dC", 1); // move cursor right
|
shiftright(1);
|
||||||
position++;
|
position++;
|
||||||
}
|
}
|
||||||
|
moved = true;
|
||||||
|
break;
|
||||||
} else if (arrow_key == 68) { // left
|
} else if (arrow_key == 68) { // left
|
||||||
if (position > 0) {
|
if (position >= 1) {
|
||||||
printf("\033[%dD", 1); // move cursor right
|
shiftleft(1);
|
||||||
position--;
|
position--;
|
||||||
}
|
}
|
||||||
} }
|
moved = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if (c > 31 && c < 127) {
|
if (c > 31 && c < 127) {
|
||||||
if (position == buf_len) {
|
if (position == buf_len) {
|
||||||
// Append character to the end of the buffer
|
// Append character to the end of the buffer
|
||||||
buffer[buf_len] = c;
|
buffer[buf_len] = c;
|
||||||
buffer[buf_len + 1] = '\0';
|
buffer[buf_len + 1] = '\0';
|
||||||
|
moved = false;
|
||||||
|
navigated = false;
|
||||||
} else {
|
} else {
|
||||||
// Insert character at the current position
|
// Insert character at the current position
|
||||||
memmove(&buffer[position + 1], &buffer[position], buf_len - position + 1);
|
memmove(&buffer[position + 1], &buffer[position], buf_len - position + 1);
|
||||||
buffer[position] = c;
|
buffer[position] = c;
|
||||||
printf("\033[s"); // Save cursor position
|
shiftright(1);
|
||||||
printf("%s", &buffer[position]); // Print from the current position
|
insertatmiddle = true;
|
||||||
printf("\033[u"); // Restore cursor position
|
|
||||||
printf("\033[%dC", 1); // move cursor right by one place
|
|
||||||
}
|
}
|
||||||
position++;
|
position++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (navigated && buf_len >= 1) {
|
||||||
|
if (position != 0) {
|
||||||
|
shiftleft(buf_len); // move cursor to the beginning
|
||||||
|
printf("\033[K"); // clear line to the right of cursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf_len = strlen(buffer);
|
||||||
|
if (moved) {
|
||||||
|
moved = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!navigated) {
|
||||||
|
if (position != buf_len) {
|
||||||
|
// not at normal place
|
||||||
|
if (backspaced) {
|
||||||
|
shiftleft(position + 1);
|
||||||
|
} else {
|
||||||
|
shiftleft(position); // move cursor to the beginning
|
||||||
|
}
|
||||||
|
} else if (buf_len > 1) {
|
||||||
|
if (backspaced) {
|
||||||
|
shiftleft(buf_len + 1); // move cursor to the beginning
|
||||||
|
} else {
|
||||||
|
shiftleft(buf_len - 1); // move cursor to the beginning
|
||||||
|
}
|
||||||
|
} else if (buf_len == 1) {
|
||||||
|
if (backspaced) {
|
||||||
|
shiftleft(2);
|
||||||
|
}
|
||||||
|
} else if (buf_len == 0) {
|
||||||
|
if (backspaced) {
|
||||||
|
shiftleft(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\033[K"); // clear line to the right of cursor
|
||||||
|
} else {
|
||||||
|
navigated = false;
|
||||||
|
}
|
||||||
char *cmd_part = strchr(buffer, ' ');
|
char *cmd_part = strchr(buffer, ' ');
|
||||||
char *command_without_arg = NULL;
|
char *command_without_arg = NULL;
|
||||||
int cmd_len = 0;
|
int cmd_len = 0;
|
||||||
|
@ -183,8 +245,8 @@ char *readline(char **paths) {
|
||||||
|
|
||||||
if (cmd_part != NULL) {
|
if (cmd_part != NULL) {
|
||||||
cmd_len = cmd_part - buffer;
|
cmd_len = cmd_part - buffer;
|
||||||
char *cmd = malloc(sizeof(char) * cmd_len + 1);
|
char *cmd = malloc(sizeof(char) * (cmd_len + 1));
|
||||||
command_without_arg = malloc(sizeof(char) * cmd_len + 1);
|
command_without_arg = malloc(sizeof(char) * (cmd_len + 1));
|
||||||
if (cmd == NULL || command_without_arg == NULL) {
|
if (cmd == NULL || command_without_arg == NULL) {
|
||||||
fprintf(stderr, "rush: Error allocating memory\n");
|
fprintf(stderr, "rush: Error allocating memory\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
@ -196,6 +258,7 @@ char *readline(char **paths) {
|
||||||
cmd[cmd_len] = '\0';
|
cmd[cmd_len] = '\0';
|
||||||
command_without_arg[cmd_len] = '\0';
|
command_without_arg[cmd_len] = '\0';
|
||||||
valid = find_command(paths, cmd);
|
valid = find_command(paths, cmd);
|
||||||
|
free(cmd);
|
||||||
} else {
|
} else {
|
||||||
valid = find_command(paths, buffer);
|
valid = find_command(paths, buffer);
|
||||||
}
|
}
|
||||||
|
@ -214,11 +277,22 @@ char *readline(char **paths) {
|
||||||
printf("\x1b[38;2;243;139;168m%s\x1b[0m\x1b[38;2;255;255;255m%s\x1b[0m", command_without_arg, buffer); // print green as valid command, but only color the command, not the arguments
|
printf("\x1b[38;2;243;139;168m%s\x1b[0m\x1b[38;2;255;255;255m%s\x1b[0m", command_without_arg, buffer); // print green as valid command, but only color the command, not the arguments
|
||||||
buffer -= cmd_len;
|
buffer -= cmd_len;
|
||||||
} else {
|
} else {
|
||||||
printf("\x1b[38;2;243;139;168m%s\x1b[0m", buffer); // print red as sinvalid command
|
printf("\x1b[38;2;243;139;168m%s\x1b[0m", buffer); // print red as invalid command
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
free(command_without_arg);
|
||||||
|
|
||||||
|
if (backspaced) {
|
||||||
|
if (buf_len != position) {
|
||||||
|
shiftleft(buf_len - position);
|
||||||
|
}
|
||||||
|
backspaced = false;
|
||||||
|
}
|
||||||
|
if (insertatmiddle) {
|
||||||
|
shiftleft(buf_len - position); // move cursor back to where it was
|
||||||
|
insertatmiddle = false;
|
||||||
|
|
||||||
|
}
|
||||||
// If we have exceeded the buffer, reallocate.
|
// If we have exceeded the buffer, reallocate.
|
||||||
if ((buf_len + 1) >= bufsize) {
|
if ((buf_len + 1) >= bufsize) {
|
||||||
bufsize += RL_BUFSIZE;
|
bufsize += RL_BUFSIZE;
|
||||||
|
@ -317,6 +391,7 @@ int main(int argc, char **argv) {
|
||||||
command_loop(paths);
|
command_loop(paths);
|
||||||
|
|
||||||
// cleanup
|
// cleanup
|
||||||
|
free(paths);
|
||||||
change_terminal_attribute(0); // change back to default settings
|
change_terminal_attribute(0); // change back to default settings
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue